首页
社区
课程
招聘
虚拟键盘、虚拟鼠标驱动
发表于: 2008-10-9 16:46 196252

虚拟键盘、虚拟鼠标驱动

2008-10-9 16:46
196252

能够在设备管理器中模拟出虚拟鼠标和键盘的驱动程序。


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

上传的附件:
收藏
免费 8
支持
分享
最新回复 (147)
雪    币: 5283
活跃值: (3669)
能力值: ( LV13,RANK:283 )
在线值:
发帖
回帖
粉丝
2
学习了,谢谢.
2008-10-9 21:57
0
雪    币: 471
活跃值: (4003)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
3
收藏再说,谢谢了
2008-10-11 09:01
0
雪    币: 364
活跃值: (152)
能力值: ( LV12,RANK:450 )
在线值:
发帖
回帖
粉丝
4
多谢了啊!!
2008-10-11 18:48
0
雪    币: 234
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
收藏了 有机会看看
2008-10-13 18:02
0
雪    币: 20
活跃值: (37)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
6
谢谢阿!学习一下
2008-10-15 11:40
0
雪    币: 445
活跃值: (52)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
7
谢谢了呀
2008-10-20 10:38
0
雪    币: 224
活跃值: (157)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
Thanks for your sharing
2008-10-20 23:54
0
雪    币: 208
活跃值: (40)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
9
谢谢,先收藏了!
2008-10-22 20:29
0
雪    币: 222
活跃值: (10)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
10
照着那个格式写个Port Driver,Device就PointerPort,给MouClass挂上,Class连接之后是取Attribute然后Read,将8042那个精简一下就可以了
2008-10-23 15:57
0
雪    币: 560
活跃值: (359)
能力值: ( LV13,RANK:1370 )
在线值:
发帖
回帖
粉丝
11
楼上的能不能讲具体点或者发份样品出来。
2008-11-6 11:31
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
找了这篇文,看对你有没有帮助,另外请联系我QQ634308587 一起研究一下。

一个鼠标驱动程序的分析(/driver/input/mouse/amimouse.c)

一:Input设备驱动,(我称为虚拟输入设备)//drivers/input/input.c文件
         input设备是一种字符设备在模块初始化时创建设备类"input",注册Input字符设备,input的操作函数只有Open函数。当打开特定设备时才将特定的设备操作函数
         static struct file_operations input_fops = {
        .owner = THIS_MODULE,
                .open = input_open_file,
        };
函数调用如下:
“/input/input . c”
input_init()//这是虚拟输入设备的入口,既模块加载时调用
{
        class_simple_create(THIS_MODULE,"input");//创建设备类
        input_proc_init()//创建proc下的文件节点
                retval = register_chrdev(INPUT_MAJOR, "input", &input_fops);//注册字符设备驱动程序,在系统字符设备数组中添加一个字符设备,主设备号为INPUT—MAJOR,操作函数集为input_fops,在特殊文件打开时会根据文件的节点结构INODE中的主设备号在系统字符设备数组中搜索主设备号相同的字符设备驱动程序的操作函数集并将此操作函数集付给FILE结构的操作函数集指针f_ops并执行该函数集中的打开操作。。对于本input类设备即为input_fops中的input_open_file
        devfs_mk_dir("input")//在设备目录"/dev"下创建devfs文件系统的"input"目录,以后的具体输入设备也将在这个目录下建立特殊设备文件,当打开该特殊文件时即对设备进行操作
}
当打开具体文件时既执行input_ipen_file此函数会寻到具体设备的文件操作函数集并付给file->f_op(这是一个文件的操作函数集,当系统打开一个文件时即产生一个file结构对该文件的操作都通过file中的f_opes 如读取即调用FILE->f_op->read等
二:输入驱动器,输入驱动器是指一类的输入设备(比如鼠标输入驱动器,键盘输入驱动器等等)这里说的是鼠标输入驱动器。。(我也称之为虚拟鼠标驱动器,因为他并不完成真正的硬件相关的鼠标驱动,真正的硬件IO驱动要在device中完成)他的描述结构是:
struct input_handler {
                void *private;//私有数据
                void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);//响应输入事件的函数
        struct input_handle* (*connect)(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id);//连接设备的函数
           void (*disconnect)(struct input_handle *handle);//断开设备
           struct file_operations *fops;//文件操作函数集
           int minor;//次设备号
           char *name;//设备名
                .....
};
static struct mousedev *mousedev_table[MOUSEDEV_MINORS];
static struct input_handler mousedev_handler = {
            .event =        mousedev_event,//鼠标事件回调函数
                .connect =        mousedev_connect,//连接device
                .disconnect =        mousedev_disconnect,
                .fops =                &mousedev_fops,//文件操作函数集
                .minor =        MOUSEDEV_MINOR_BASE,//次设备号基数
                .name =                "mousedev",//设备名
                .id_table =        mousedev_ids,//本驱动支持的设备ID
};
他的入口是:
“/input/mousedev . c”
static int __init mousedev_init(void)
{
        input_register_handler(&mousedev_handler);//在虚拟输入设备中注册鼠标输入驱动器
        memset(&mousedev_mix, 0, sizeof(struct mousedev));
        INIT_LIST_HEAD(&mousedev_mix.list);
        init_waitqueue_head(&mousedev_mix.wait);
        mousedev_table[MOUSEDEV_MIX] = &mousedev_mix;//给设备数组一个默认的鼠标device
        mousedev_mix.exist = 1;
        mousedev_mix.minor = MOUSEDEV_MIX;
        devfs_mk_cdev(MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + MOUSEDEV_MIX),
        S_IFCHR|S_IRUGO|S_IWUSR, "input/mice");//建立input/mice文件
        class_simple_device_add(input_class, MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + MOUSEDEV_MIX),
                NULL, "mice");//在input_class设备类中增加本设备驱动程序
        printk(KERN_INFO "mice: PS/2 mouse device common for all mice\n");
        return 0;
}
虚拟鼠标设备驱动器就提供了各种操作的操作集函数,如read,write,ioctrl,等
static struct file_operations mousedev_fops = {
        .owner =        THIS_MODULE,
                .read =                mousedev_read,
                .write =        mousedev_write,
                .poll =                mousedev_poll,
                .open =                mousedev_open,
                .release =        mousedev_release,
                .fasync =        mousedev_fasync,
};
“/input/input . c”
void input_register_handler(struct input_handler *handler)
{
        struct input_dev *dev;//具体设备描述结构
        struct input_handle *handle;//设备句柄
        struct input_device_id *id;//设备ID
        if (!handler) return;
        INIT_LIST_HEAD(&handler->h_list);//初始化设备驱动器的链表
        if (handler->fops != NULL)
        input_table[handler->minor >> 5] = handler;//把驱动器按次设备号放到驱动器数组里,虚拟设备支持最多8个次设备
        list_add_tail(&handler->node, &input_handler_list);//加入驱动器链表
        list_for_each_entry(dev, &input_dev_list, node)
                if (!handler->blacklist || !input_match_device(handler->blacklist, dev))
                if ((id = input_match_device(handler->id_table, dev)))//用当前所有的输入设备于驱动器适配
                                if ((handle = handler->connect(handler, dev, id)))//适配成功与驱动器连接
                                        input_link_handle(handle);//连接成功将设备句柄加到设备的句柄链表中
}
我们先假设注册驱动器时还没有一个输入设备在链表中,即注册时不需要进行驱动器适配。在后面设备注册时再讲适配连接
这样就完成了一个驱动器的注册
三,具体设备。。
这里完成的是真实与硬件交互的设备程序。。设备的描述结构是input_dev
struct input_dev {
        void *private;//私有数据
        char *name;//
        ......
        int (*open)(struct input_dev *dev);
        void (*close)(struct input_dev *dev);
        int (*accept)(struct input_dev *dev, struct file *file);
        int (*flush)(struct input_dev *dev, struct file *file);
        int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);
        int (*upload_effect)(struct input_dev *dev, struct ff_effect *effect);
        int (*erase_effect)(struct input_dev *dev, int effect_id);//都是些回调函数了
        struct input_handle *grab;//设备句柄
        struct device *dev;//通用设备结构
        struct list_head        h_list;//句柄链表input_link_handle函数将设备句柄加入到链表中。dev响应中断时如果没有自己专用的event函数就遍历handle列表找到handle指向的input_handler的evnt函数调用
        struct list_head        node;
};
struct input_handle {
        void *private;//私有数据
        int open;
        char *name;
        struct input_dev *dev;//设备
        struct input_handler *handler;//句柄拥有者驱动器
        struct list_head        d_node;
        struct list_head        h_node;
};
它的入口是:
“/input/mouse/amimouse . c”
static int __init amimouse_init(void)
{
        if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(AMI_MOUSE))
                return -ENODEV;
        amimouse_dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
        amimouse_dev.relbit[0] = BIT(REL_X) | BIT(REL_Y);
        amimouse_dev.keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
        amimouse_dev.open = amimouse_open;
        amimouse_dev.close = amimouse_close;
       
        amimouse_dev.name = amimouse_name;
        amimouse_dev.phys = amimouse_phys;
        amimouse_dev.id.bustype = BUS_AMIGA;
        amimouse_dev.id.vendor = 0x0001;
        amimouse_dev.id.product = 0x0002;
        amimouse_dev.id.version = 0x0100;
       
        input_register_device(&amimouse_dev);//注册设备
       
        printk(KERN_INFO "input: %s at joy0dat\n", amimouse_name);
        return 0;
}
“/input/input . c”
void input_register_device(struct input_dev *dev)
{
        struct input_handle *handle;
        struct input_handler *handler;
        struct input_device_id *id;
        /*
        * If delay and period are pre-set by the driver, then autorepeating
        * is handled by the driver itself and we don't do it in input.c.
        */
        init_timer(&dev->timer);//初始化设备的定时器,对鼠标没什么用mousedev里没对他做什么,对键盘有用
        if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) {
                dev->timer.data = (long) dev;
                dev->timer.function = input_repeat_key;
                dev->rep[REP_DELAY] = 250;
                dev->rep[REP_PERIOD] = 33;
        }
        INIT_LIST_HEAD(&dev->h_list);//初始化设备的句柄链表
        list_add_tail(&dev->node, &input_dev_list);
       
        list_for_each_entry(handler, &input_handler_list, node)//遍历驱动器列表
        if (!handler->blacklist || !input_match_device(handler->blacklist, dev))  
        if ((id = input_match_device(handler->id_table, dev)))//找到与设备相配的驱动器,用id_table适配
        if ((handle = handler->connect(handler, dev, id)))//适配成功与驱动器连接// 这里是mouse驱动器mousedev的connect函数是mousedev_connect
input_link_handle(handle);//把Mousedev返回input_handle(注意不是input_handler)加到dev的handle连表中//这样dev响应中断时如果没有自己专用的event函数就遍历handle列表找到handle指向的input_handler的evnt函数调用                               
#ifdef CONFIG_HOTPLUG
                                input_call_hotplug("add", dev);
#endif
                                #ifdef CONFIG_PROC_FS
                                input_devices_state++;
                                wake_up(&input_devices_poll_wait);
#endif
}
看看驱动器是怎么连接设备的,他申请一个mousedev结构用来保存鼠标设备信息。将设备和设备句柄及input_handler联系起来放在mousedev_table指针数组中并给每个mousedev分配一个ID minor进行唯一标志
struct mousedev {
        int exist;//设备是否存在
        int open;//
        int minor;
        char name[16];
        wait_queue_head_t wait;//等待队列
        struct list_head list;//打开mousdev的文件的列表
        struct input_handle handle;//设备句柄-       
        struct mousedev_hw_data packet;
        unsigned int pkt_count;
        int old_x[4], old_y[4];
        int frac_dx, frac_dy;
        unsigned long touch;
};
struct input_handle {
        void *private;
        int open;
        char *name;
        struct input_dev *dev;
        struct input_handler *handler;
        struct list_head        d_node;
        struct list_head        h_node;
};
“/input/mousedev . c”
static struct input_handle *mousedev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id)
{
        struct mousedev *mousedev;
        int minor = 0;
        for (minor = 0; minor < MOUSEDEV_MINORS && mousedev_table[minor]; minor++);
        if (minor == MOUSEDEV_MINORS) {
                printk(KERN_ERR "mousedev: no more free mousedev devices\n");
                return NULL;
        }
        if (!(mousedev = kmalloc(sizeof(struct mousedev), GFP_KERNEL)))
                return NULL;
        memset(mousedev, 0, sizeof(struct mousedev));
       
        INIT_LIST_HEAD(&mousedev->list);
        init_waitqueue_head(&mousedev->wait);
       
        mousedev->minor = minor;
        mousedev->exist = 1;
        mousedev->handle.dev = dev;
        mousedev->handle.name = mousedev->name;
        mousedev->handle.handler = handler;
        mousedev->handle.private = mousedev;
        sprintf(mousedev->name, "mouse%d", minor);
        if (mousedev_mix.open)
        input_open_device(&mousedev->handle);//看默认的mousedev是否需要打开,如果需要就打开设备。
        mousedev_table[minor] = mousedev;
        devfs_mk_cdev(MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor),
        S_IFCHR|S_IRUGO|S_IWUSR, "input/mouse%d", minor);建立设备文件
        class_simple_device_add(input_class,
        MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor),
        dev->dev, "mouse%d", minor);
        return &mousedev->handle;
}
所有的注册已经完成
四:设备控制。。。。
打开设备。
当系统打开一个设备时 如"/dev/input/mouse0",虚拟文件系统根据文件节点INODE中的主设备
号在系统字符设备数组中搜索主设备号相同的字符设备驱动程序的操作函数集并将此操作函数集付给FILE结构的操作函数集指针f_ops并执行该函数集中的打开操作。。对于input类设备即为input_fops中的input_open_file
“/input/input . c”
static int input_open_file(struct inode *inode, struct file *file)
{
        struct input_handler *handler = input_table[iminor(inode) >> 5];//根据次设备号找到驱动器这里我们就假设是打开
        鼠标既找到了mousedev_handler
        struct file_operations *old_fops, *new_fops = NULL;
        int err;
       
        /* No load-on-demand here? */
        if (!handler || !(new_fops = fops_get(handler->fops)))//得到输入驱动器的操作函数集//输入驱动器。可以是一个鼠标输入驱动器
                //或者一个键盘输入驱动器,这里分析的是鼠标
                return -ENODEV;
        /*
                * That's _really_ odd. Usually NULL ->open means "nothing special",
                * not "no device". Oh, well...
        */
        if (!new_fops->open) {//如果输入驱动器没有打开操作函数,既设备文件无法完成打开操作
                fops_put(new_fops);
                return -ENODEV;
        }
        old_fops = file->f_op;
        file->f_op = new_fops;//将句柄的操作函数集给file->f_op
        err = new_fops->open(inode, file);//执行输入驱动器的打开操作
        if (err) {
                fops_put(file->f_op);
                file->f_op = fops_get(old_fops);
        }
        fops_put(old_fops);
        return err;
}
联系err = new_fops->open(inode, file);
和static struct input_handler mousedev_handler = {
        .event =        mousedev_event,//鼠标事件回调函数
                .connect =        mousedev_connect,//连接device
                .disconnect =        mousedev_disconnect,
                .fops =                &mousedev_fops,//文件操作函数集
                .minor =        MOUSEDEV_MINOR_BASE,//次设备号基数
                .name =                "mousedev",//设备名
                .id_table =        mousedev_ids,//本驱动支持的设备ID
};
这个就相当于调用mousedev_handler.fops中的函数也即mousedev_fops的函数,
而mousedev_fops的open函数是mousedev_open
分配一个mousedev_list结构保存给file结构的私有数据
mousedev_list里保存了一个mousedev结构。。而mousedev也有个文件链表。这样当
中断发生时可以根据链表反向找到file结构,而后驱动器打开他拥有并存在的未打开的所有设备句柄
调用了input_open_device函数
“/input/mousedev . c”
static int mousedev_open(struct inode * inode, struct file * file)
{
        struct mousedev_list *list;
        struct input_handle *handle;
        struct mousedev *mousedev;
        int i;
       
#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
        if (imajor(inode) == MISC_MAJOR)
                i = MOUSEDEV_MIX;
        else
#endif
                i = iminor(inode) - MOUSEDEV_MINOR_BASE;
       
        if (i >= MOUSEDEV_MINORS || !mousedev_table[i])
                return -ENODEV;
       
        if (!(list = kmalloc(sizeof(struct mousedev_list), GFP_KERNEL)))
                return -ENOMEM;
        memset(list, 0, sizeof(struct mousedev_list));
       
        spin_lock_init(&list->packet_lock);
        list->pos_x = xres / 2;
        list->pos_y = yres / 2;
        list->mousedev = mousedev_table[i];
        list_add_tail(&list->node, &mousedev_table[i]->list);
        file->private_data = list;
       
        if (!list->mousedev->open++) {
                if (list->mousedev->minor == MOUSEDEV_MIX) {
                        list_for_each_entry(handle, &mousedev_handler.h_list, h_node) {
                                mousedev = handle->private;
                                if (!mousedev->open && mousedev->exist)
                                        input_open_device(handle);
                        }
                } else
                        if (!mousedev_mix.open && list->mousedev->exist)
                                input_open_device(&list->mousedev->handle);
        }
       
        return 0;
}
input_open_device 调用设柄句柄中保存的设备指针的open函数直接打开设备
“/input/input . c”
int input_open_device(struct input_handle *handle)//在mousedev里的mousedevopen调用
{
        handle->open++;
        if (handle->dev->open)
                return handle->dev->open(handle->dev);//调用具体设备的OPEN比如amimouse里的Open
        return 0;
}
这就相当于打开了第三节中input_dev::open函数既amimouse_open函数
amimouse_open函数为设备申请了中断资源并设定了中断服务程序amimouse_interrupt
“/input/mouse/amimouse . c”
static int amimouse_open(struct input_dev *dev)
{
        unsigned short joy0dat;
       
        if (amimouse_used++)
                return 0;
       
        joy0dat = custom.joy0dat;
       
        amimouse_lastx = joy0dat & 0xff;
        amimouse_lasty = joy0dat >> 8;
       
        if (request_irq(IRQ_AMIGA_VERTB, amimouse_interrupt, 0, "amimouse", amimouse_interrupt)) {
                amimouse_used--;
                printk(KERN_ERR "amimouse.c: Can't allocate irq %d\n", IRQ_AMIGA_VERTB);
                return -EBUSY;
        }
       
        return 0;
}
中断服务程序amimouse_interrupt从内存得到数据//amimouse中断发生时会把数据存在一块固定地址
通过input_report_rel等函数通知设备已获得数据
“/input/mouse/amimouse . c”
static irqreturn_t amimouse_interrupt(int irq, void *dummy, struct pt_regs *fp)
{
/**/
                unsigned short joy0dat, potgor;
        int nx, ny, dx, dy;
       
        joy0dat = custom.joy0dat;
       
        nx = joy0dat & 0xff;
        ny = joy0dat >> 8;
       
        dx = nx - amimouse_lastx;
        dy = ny - amimouse_lasty;
       
        if (dx < -127) dx = (256 + nx) - amimouse_lastx;
        if (dx >  127) dx = (nx - 256) - amimouse_lastx;
        if (dy < -127) dy = (256 + ny) - amimouse_lasty;
        if (dy >  127) dy = (ny - 256) - amimouse_lasty;
       
        amimouse_lastx = nx;
        amimouse_lasty = ny;
       
        potgor = custom.potgor;
        input_regs(&amimouse_dev, fp);
       
        input_report_rel(&amimouse_dev, REL_X, dx);
        input_report_rel(&amimouse_dev, REL_Y, dy);
       
        input_report_key(&amimouse_dev, BTN_LEFT,   ciaa.pra & 0x40);
        input_report_key(&amimouse_dev, BTN_MIDDLE, potgor & 0x0100);
        input_report_key(&amimouse_dev, BTN_RIGHT,  potgor & 0x0400);
       
        input_sync(&amimouse_dev);
        .......
        return IRQ_HANDLED;
}

input_report_rel,input_report_key函数只是简单调用input_event函数
“/linux/input.h”
static inline void input_report_rel(struct input_dev *dev, unsigned int code, int value)
{
        input_event(dev, EV_REL, code, value);
}
如果设备自已有专用event函数既input_dev结构中event非空 input_event调用event函数
如果与设备相关的设备句柄是唯一指定的保存在grab中就调用该句柄所指向的驱动器handler的event函数
否则遍历设备设备句柄链表调用句柄指向的驱动器event函数。。
这里因为amimouse没有专属的event函数而grab在input_register_device时在mousedev_connect函数中也没给值,
但其返回的设备句柄在设备的句柄链表里。所以会调用mousedev驱动器的event函数既mousedev_event函数
“/input/input . c”
void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{
        struct input_handle *handle;

        if (type > EV_MAX || !test_bit(type, dev->evbit))
                return;

        add_input_randomness(type, code, value);
        switch (type) {

                case EV_SYN:
                        switch (code) {
                                case SYN_CONFIG:
                                        if (dev->event) dev->event(dev, type, code, value);
                                        break;
                                        ...
                                        ...
                                        ...
                        }
                        break;
        }
        if (dev->grab)
                dev->grab->handler->event(dev->grab, type, code, value);
        else
                list_for_each_entry(handle, &dev->h_list, d_node)
                        if (handle->open)
                                handle->handler->event(handle, type, code, value);//见line 439
}

“/input/mousedev . c”
static void mousedev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
{
        struct mousedev *mousedev = handle->private;//在mousedev_connect中给handle的私有变量的mousedev指针
       
        switch (type) {
                ....
        case EV_SYN:
                if (code == SYN_REPORT) {
                        if (mousedev->touch) {
                                mousedev->pkt_count++;
                                /* Input system eats duplicate events, but we need all of them
                                * to do correct averaging so apply present one forward
                                */
                                fx(0) = fx(1);
                                fy(0) = fy(1);
                        }
                       
                        mousedev_notify_readers(mousedev, &mousedev->packet);//通知设备有数据到达读取
                       
                        mousedev->packet.dx = mousedev->packet.dy = mousedev->packet.dz = 0;
                        mousedev->packet.abs_event = 0;
                }
                break;
        case EV_REL:
                mousedev_rel_event(mousedev, code, value);
                /****/
                break;
                ....
        }
}
static void mousedev_rel_event(struct mousedev *mousedev, unsigned int code, int value)
{
        switch (code) {
        case REL_X:        mousedev->packet.dx += value; break;
        case REL_Y:        mousedev->packet.dy -= value; break;
        case REL_WHEEL:        mousedev->packet.dz -= value; break;
        }
}
读取鼠标位置时
同打开文件一样,读取file时会调用file的f_op函数集的函数,但此是f_op已经在打开时付值为驱动器的函数集指针了。
既mousedev_fops函数集,其中的read函数为mousedev_read,他在本设备等待有输入发生。
“/input/mousedev . c”
static ssize_t mousedev_read(struct file * file, char __user * buffer, size_t count, loff_t *ppos)
{
        struct mousedev_list *list = file->private_data;
        int retval = 0;
       
        if (!list->ready && !list->buffer && (file->f_flags & O_NONBLOCK))
                return -EAGAIN;
       
        retval = wait_event_interruptible(list->mousedev->wait,
                !list->mousedev->exist || list->ready || list->buffer);
       
        if (retval)
                return retval;
       
        if (!list->mousedev->exist)
                return -ENODEV;
       
        if (!list->buffer && list->ready) {
                mousedev_packet(list, list->ps2);
                list->buffer = list->bufsiz;
        }
       
        if (count > list->buffer)
                count = list->buffer;
       
        list->buffer -= count;
       
        if (copy_to_user(buffer, list->ps2 + list->bufsiz - list->buffer - count, count))
                return -EFAULT;
       
        return count;
}
通过mousedev->list遍历打开本设备的所有mousedev_list结构并对他们付值,mousedev_list结构是在打开设备时链接进list的,而在打开此设备的文件描述符File中的privatedata指向些list指针。。。而后置list->ready为真表有数据到达,再唤醒一个在本设备等待读数据的进程
“/input/mousedev . c”
static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_hw_data *packet)
{
        struct mousedev_list *list;
        struct mousedev_motion *p;
        unsigned long flags;
       
        list_for_each_entry(list, &mousedev->list, node) {
                spin_lock_irqsave(&list->packet_lock, flags);
               
                p = &list->packets[list->head];
                if (list->ready && p->buttons != mousedev->packet.buttons) {
                        unsigned int new_head = (list->head + 1) % PACKET_QUEUE_LEN;
                        if (new_head != list->tail) {
                                p = &list->packets[list->head = new_head];
                                memset(p, 0, sizeof(struct mousedev_motion));
                        }
                }
               
                if (packet->abs_event) {
                        p->dx += packet->x - list->pos_x;
                        p->dy += packet->y - list->pos_y;
                        list->pos_x = packet->x;
                        list->pos_y = packet->y;
                }
               
                list->pos_x += packet->dx;
                list->pos_x = list->pos_x < 0 ? 0 : (list->pos_x >= xres ? xres : list->pos_x);
                list->pos_y += packet->dy;
                list->pos_y = list->pos_y < 0 ? 0 : (list->pos_y >= yres ? yres : list->pos_y);
               
                p->dx += packet->dx;
                p->dy += packet->dy;
                p->dz += packet->dz;
                p->buttons = mousedev->packet.buttons;
               
                if (p->dx || p->dy || p->dz || p->buttons != list->last_buttons)
                        list->ready = 1;
               
                spin_unlock_irqrestore(&list->packet_lock, flags);
               
                if (list->ready)
                        kill_fasync(&list->fasync, SIGIO, POLL_IN);
        }
       
        wake_up_interruptible(&mousedev->wait);
}
2009-1-22 02:22
0
雪    币: 177
活跃值: (232)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
13
期待成型的源码出来
2009-1-23 00:01
0
雪    币: 254
活跃值: (10)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
14
很好很强大,努力学习中.还在学C.菜鸟在飞
2009-1-29 17:46
0
雪    币: 231
活跃值: (45)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
qdk
15
顶一下,谢谢分享
2009-1-29 21:24
0
雪    币: 221
活跃值: (12)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
网络游戏出于对控制输入速度的和反外挂的目的,对于鼠标键盘的输入越过了消息传递等正常的途径层
次,所以一般的常用如下控制鼠标键盘的API函数
::SetCursorPos(pEvent->xPos, pEvent->yPos);
::SendInput(1, &Input, sizeof(INPUT));
::PostMessage(hwnd,WM_KEYDOWN, VK_ESC ,0L); //发送ESC按下的键盘消息

是无法实现目的的,解决问题的方法只有越过应用层面,从系统驱动层解决问题,目前的方法主要有
1.分别写个鼠标和键盘驱动设备,但在在系统设备管理器中出现一个鼠标和一个键盘设备
2.用winio软件包直接控制鼠标键盘硬件端口,这种方法要求本身的硬件鼠标不可以动,否则就鼠标满天
飞,只有重启电脑了
结合外挂的特点和以上方法优缺点,本人在底层修改window底层驱动,鼠标键盘驱动合二为一可以同时
控制鼠标键盘,可以打开和关闭屏蔽物理鼠标,可以过滤键盘信息,并且在系统设备管理器中也看不到
设备显示,即隐蔽又高效,有需要的朋友可以联系,

该驱动为自己开发外挂而制作,当时也考虑购买但是没有人卖,无法买到,所以今天提供给大家,
该驱动完全为外挂的高要求而制作测试使用验证成熟,可以玩转鼠标键盘摆脱API函数的限制,做出
各种复杂的鼠标键盘动作,明白人一看下面的鼠标键盘控制数据结构就明白了。。总之windows
APi可以干的事情,它都可以干,它可以做的动作windows APi就不行了

电话qq76838567 (验证信息请注明”鼠标“)
控制接口如下:

typedef struct MOUSE_INPUT_DATA {
  USHORT  UnitId;
  USHORT  Flags;
  union {
    ULONG  Buttons;
      struct {
         USHORT  ButtonFlags;
         USHORT  ButtonData;
      };
  };
  ULONG  RawButtons;
  LONG  LastX;
  LONG  LastY;
  ULONG  ExtraInformation;
} MOUSE_INPUT_DATA, *PMOUSE_INPUT_DATA;

typedef struct _KEYBOARD_INPUT_DATA {
  USHORT  UnitId;
  USHORT  MakeCode;
  USHORT  Flags;
  USHORT  Reserved;
  ULONG  ExtraInformation;
} KEYBOARD_INPUT_DATA, *PKEYBOARD_INPUT_DATA;

long Move_Ext(long x, long y)
{
MOUSE_INPUT_DATA  INPUT_DATA ;
UCHAR OutputBuffer[10];
DWORD dwOutput;
BOOL bRet;

    if (hDevice == INVALID_HANDLE_VALUE) return 0;

    memset(&INPUT_DATA,0,sizeof(MOUSE_INPUT_DATA));
   
    INPUT_DATA.Flags=MOUSE_MOVE_RELATIVE;

    INPUT_DATA.LastX=x;

    INPUT_DATA.LastY=y;
   
    bRet = DeviceIoControl(hDevice, IOCTL_Mouse, (char*)&INPUT_DATA, sizeof(MOUSE_INPUT_DATA), &OutputBuffer, 10, &dwOutput, NULL);

    return bRet;

}
long Click_EXT(char Action)
{
MOUSE_INPUT_DATA  INPUT_DATA ;
UCHAR OutputBuffer[10];
DWORD dwOutput;
BOOL bRet;

    if (hDevice == INVALID_HANDLE_VALUE) return 0;

    memset(&INPUT_DATA,0,sizeof(MOUSE_INPUT_DATA));
   
    INPUT_DATA.Flags=MOUSE_MOVE_RELATIVE;

    INPUT_DATA.ButtonFlags=Action;
    bRet = DeviceIoControl(hDevice, IOCTL_Mouse, (char*)&INPUT_DATA, sizeof(MOUSE_INPUT_DATA), &OutputBuffer, 10, &dwOutput, NULL);

    return bRet;
}

long KeyBoard(long MakeCode, long Flags)
{
KEYBOARD_INPUT_DATA  INPUT_DATA ;
UCHAR OutputBuffer[10];
DWORD dwOutput;
BOOL bRet;

    if (hDevice == INVALID_HANDLE_VALUE) return 0;

    memset(&INPUT_DATA,0,sizeof(KEYBOARD_INPUT_DATA));
   
    INPUT_DATA.Flags=Flags;

    INPUT_DATA.MakeCode=MakeCode;

   
    bRet = DeviceIoControl(hDevice, IOCTL_KeyBoard, (char*)&INPUT_DATA, sizeof(KEYBOARD_INPUT_DATA), &OutputBuffer, 10, &dwOutput, NULL);

    return bRet;

}
//                    扫描码   
#define     VKK_ESC    0x011b    //ESC
#define     VKK_F1        0x3b00    //F1
#define     VKK_F2        0x3c00    //F2
#define     VKK_F3        0x3d00    //F3
#define     VKK_F4        0x3e00    //F4
#define     VKK_F5        0x3f00    //F5
#define     VKK_F6        0x4000    //F6
#define     VKK_F7        0x4100    //F7
#define     VKK_F8        0x4200    //F8
#define     VKK_F9        0x4300    //F9
#define     VKK_F10    0x4400    //F10
#define     VKK_~        0x2960    //~
#define     VKK_1        0x0231    //1
#define     VKK_2        0x0332    //2
#define     VKK_3        0x0433    //3
#define     VKK_4        0x0534    //4
#define     VKK_5        0x0635    //5
#define     VKK_6        0x0736    //6
#define     VKK_7        0x0837    //7
#define     VKK_8        0x0938    //8
#define     VKK_9        0x0a39    //9
#define     VKK_0        0x0b30    //0
#define     VKK_-        0x0c2d    //-
#define     VKK_=        0x0d3d    //=
#define     VKK_\        0x2b5c    //\
#define     VKK_BackSpace    0x0e08    //退格键
#define     VKK_Tab        0x0f09    //Tab
#define     VKK_q        0x1071    //q
#define     VKK_w        0x1177    //w
#define     VKK_e        0x1265    //e
#define     VKK_r        0x1372    //r
#define     VKK_t        0x1474    //t
#define     VKK_y        0x1579    //y
#define     VKK_u        0x1675    //u
#define     VKK_i        0x1769    //i
#define     VKK_o        0x186f    //o
#define     VKK_p        0x1970    //p
#define     VKK_[        0x1a5b    //[
#define     VKK_]        0x1b5d    //]
#define     VKK_a        0x1e61    //a
#define     VKK_s        0x1f73    //s
#define     VKK_d        0x2064    //d
#define     VKK_f        0x2166    //f
#define     VKK_g        0x2267    //g
#define     VKK_h        0x2368    //h
#define     VKK_j        0x246a    //j
#define     VKK_k        0x256b    //k
#define     VKK_l        0x266c    //l
#define     VKK_;        0x273b    //;
#define     VKK_'        0x2827    //'
#define     VKK_Enter    0x1c0d    //回车
#define     VKK_z        0x2c7a    //z
#define     VKK_x        0x2d78    //x
#define     VKK_c        0x2e63    //c
#define     VKK_v        0x2f76    //v
#define     VKK_b        0x3062    //b
#define     VKK_n        0x316e    //n
#define     VKK_m        0x326d    //m
#define     VKK_        0x332c    //
#define     VKK_.        0x342e    //.
#define     VKK_/        0x352f    ///
#define     VKK_空格键    0x3920    //空格键
#define     VKK_Insert    0x5200    //Insert
#define     VKK_Home    0x4700    //Home
#define     VKK_Page UP    0x4900    //Page UP
#define     VKK_Delete    0x5300    //Delete
#define     VKK_End    0x4f00    //End
#define     VKK_PageDown    0x5100    //PageDown
#define     VKK_上箭头    0x4800    //上箭头
#define     VKK_左箭头    0x4b00    //左箭头
#define     VKK_下箭头    0x5000    //下箭头
#define     VKK_右箭头    0x4d00    //右箭头
#define     VKK_/        0x352f    ///
#define     VKK_*        0x372a    //*
#define     VKK_- (注意    0x4a2d    //- (注意
#define     VKK_7        0x4737    //7
#define     VKK_8        0x4838    //8
#define     VKK_9        0x4939    //9
#define     VKK_4        0x4b34    //4
#define     VKK_5        0x4c35    //5
#define     VKK_6        0x4d36    //6
#define     VKK_+        0x4e2b    //+
#define     VKK_1        0x4f31    //1
#define     VKK_2        0x5032    //2
#define     VKK_3        0x5133    //3
#define     VKK_0        0x5230    //0
#define     VKK_Del        0x532e    //Del
2009-2-10 08:50
0
雪    币: 204
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
谢谢!
下完了才顶
2009-2-10 19:21
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
谢了,原始积累阶段
2009-2-11 14:08
0
雪    币: 239
活跃值: (190)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
19
他这东西,为什么在我的本本机器上不能模拟键盘呢,mouse模拟好似没有问题,但kbd不行,只看见设备,但不能模拟出来
2009-2-11 15:11
0
雪    币: 112
活跃值: (51)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
20
谢谢分享。。。
2009-2-19 19:30
0
雪    币: 135
活跃值: (76)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
21
谢谢分享.学习学习.
2009-2-20 18:31
0
雪    币: 203
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
22
学习了,谢谢laomms
2009-2-20 21:32
0
雪    币: 1594
活跃值: (113)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
23
看不懂,正在学习驱动。。。。。。。。膜拜下
2009-2-21 01:01
0
雪    币: 221
活跃值: (12)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
24
11111111111111111111111
2009-2-22 19:11
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
25
已经完成了吗?如何使用呢,不懂。
2009-2-23 12:37
0
游客
登录 | 注册 方可回帖
返回
//