能力值:
( 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);
}
能力值:
( 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