分享一个linux下用键盘模拟鼠标的驱动
用小键盘的上下左右控制鼠标,小键盘数字5模拟鼠标左键。鼠标移动速度可以通过向/sys/devices/virtual/input/inputX/speed 写入0~100之间的整数调整,默认移动速度是5像素。各位帮忙看看有什么需要改进的地方。谢谢!
/***********************************virtual-mouse.c********************************************/
#include <linux/module.h>
#include <linux/input.h>
#include <linux/init.h>
#include <linux/bitops.h>
#include <linux/mod_devicetable.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
#include <linux/spinlock.h>
MODULE_LICENSE("Dual BSD/GPL");
#define HW_RAW(dev) (test_bit(EV_MSC,dev->evbit) && test_bit(MSC_RAW,dev->mscbit) && ((dev)->id.bustype == BUS_I8042) && ((dev)->id.vendor == 0x0001) && ((dev)->id.product == 0x0001))
#define DEFAULT_SPEED 10
#define MAX_SPEED 50
#define MIN_SPEED 1
static ssize_t vms_speed(struct device *dev,struct device_attribute *attr,const char *buffer,size_t count);
DEVICE_ATTR(speed,0644,NULL,vms_speed);
struct vms
{
struct input_handler *handler;
struct input_handle *handle;
struct input_dev *dev;
//struct work_struct work;
struct attribute attr;
spinlock_t lock;
unsigned int event_code;
int value;
//unsigned int step;
unsigned int speed;
unsigned int max_speed;
unsigned int min_speed;
}*vms;
static ssize_t vms_speed(struct device *dev,struct device_attribute *attr,const char *buffer,size_t count)
{
int speed;
sscanf(buffer,"%d",&speed);
printk(KERN_ALERT "speed changed to %d\n",speed);
speed = speed<vms->min_speed ? vms->min_speed : speed;
speed = speed>vms->max_speed ? vms->max_speed : speed;
spin_lock(&vms->lock);
vms->speed = speed;
spin_unlock(&vms->lock);
return count;
}
//function for vms's work queue
void vms_func(struct work_struct *work)
{
spin_lock(&vms->lock);
switch(vms->event_code)
{
case KEY_KP8:
input_report_rel(vms->dev,REL_X,0);
input_report_rel(vms->dev,REL_Y,-vms->speed);
input_sync(vms->dev);
break;
case KEY_KP2:
input_report_rel(vms->dev,REL_X,0);
input_report_rel(vms->dev,REL_Y,vms->speed);
input_sync(vms->dev);
break;
case KEY_KP4:
input_report_rel(vms->dev,REL_X,-vms->speed);
input_report_rel(vms->dev,REL_Y,0);
input_sync(vms->dev);
break;
case KEY_KP6:
input_report_rel(vms->dev,REL_X,vms->speed);
input_report_rel(vms->dev,REL_Y,0);
input_sync(vms->dev);
break;
case KEY_KP5:
input_report_key(vms->dev,BTN_LEFT,vms->value);
input_sync(vms->dev);
break;
}
spin_unlock(&vms->lock);
printk(KERN_ALERT "vms work funcction:KEY_KP8=%d,event_code=%d\n",KEY_KP8,vms->event_code);
}
static void vkbd_event(struct input_handle *handle, unsigned int event_type,
unsigned int event_code, int value)
{
if(event_type == EV_MSC && event_code == MSC_RAW && HW_RAW(handle->dev))
printk(KERN_ALERT "RAW\n");
if(event_type == EV_KEY)
{
vms->event_code = event_code;
vms->value = value;
//printk(KERN_ALERT "XXX %d\n",HW_RAW(handle->dev));
printk(KERN_ALERT "vkbd: [%d,%d]\n", event_code ,value);
schedule_work(&vms->work);
}
}
static int vkbd_connect(struct input_handler *handler, struct input_dev *dev,
const struct input_device_id *id)
{
struct input_handle *handle;
int error;
int i;
for(i = KEY_RESERVED; i < BTN_MISC; i++)
if(test_bit(i,dev->keybit))
break;
if(i == BTN_MISC && !test_bit(EV_SND, dev->evbit))
return -ENODEV;
handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
vms->handle = handle;
if(!handle)
return -ENOMEM;
handle->dev = dev;
handle->handler = handler;
handle->name = "vkbd";
error = input_register_handle(handle);
if(error)
goto err_free_handle;
error = input_open_device(handle);
if(error)
goto err_unregister_handle;
printk(KERN_ALERT "vkbd_connect: %s\n", dev->name);
return 0;
err_unregister_handle:
input_unregister_handle(handle);
err_free_handle:
kfree(handle);
return error;
}
static void vkbd_disconnect(struct input_handle *handle)
{
input_close_device(handle);
input_unregister_handle(handle);
kfree(handle);
}
static void vkbd_start(struct input_handle *handle)
{
input_inject_event(handle,EV_LED,LED_CAPSL,0x04);
input_inject_event(handle,EV_SYN,SYN_REPORT,0);
}
static const struct input_device_id vkbd_ids[] =
{
{
.flags = INPUT_DEVICE_ID_MATCH_EVBIT,
.evbit = { BIT_MASK(EV_KEY) },
},
{
.flags = INPUT_DEVICE_ID_MATCH_EVBIT,
.evbit = { BIT_MASK(EV_SND) },
},
{
},
};
static struct input_handler vkbd_handler =
{
.event = vkbd_event,
.connect = vkbd_connect,
.disconnect = vkbd_disconnect,
.start = vkbd_start,
.name = "vkbd",
.id_table = vkbd_ids,
};
int __init vms_init(void)
{
int error;
vms = kzalloc(sizeof(struct vms),GFP_KERNEL);
vms->handler = &vkbd_handler;
INIT_WORK(&vms->work,vms_func);
spin_lock_init(&vms->lock);
//vms->step = 5;
vms->speed = DEFAULT_SPEED;
vms->max_speed = MAX_SPEED;
vms->min_speed = MIN_SPEED;
error = input_register_handler(&vkbd_handler);
if(error)
return error;
//init vms_dev
vms->dev = input_allocate_device();
if(!vms->dev)
{
printk(KERN_ALERT "vms: Bad input_allocate_device()\n");
return -1;
}
vms->dev->evbit = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
vms->dev->keybit = BIT_MASK(BTN_LEFT);
vms->dev->relbit = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
vms->dev->name = "vms";
vms->dev->phys = "vms";
vms->dev->id.bustype = BUS_I8042;
vms->dev->id.vendor = 0x0002;
vms->dev->id.product = 5;
vms->dev->id.version = 0;
//register vmose_dev
input_register_device(vms->dev);
sysfs_create_file(&vms->dev->dev.kobj,&dev_attr_speed);
printk(KERN_ALERT "vms init\n");
return 0;
}
void __exit vms_exit(void)
{
sysfs_remove_file(&vms->dev->dev.kobj,&dev_attr_speed);
if(vms->dev)
input_unregister_device(vms->dev);
input_unregister_handler(vms->handler);
kfree(vms);
}
module_init(vms_init);
module_exit(vms_exit);
/***********************************Makefile********************************************/
#ifneq ($(KERNELRELEASE),)
obj-m := vmouse.o
vmouse-objs := virtual-mouse.o
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
rm -r *.o *.mod.* *.order *.symvers *.ko Good! 从功能上来说,在用户空间直接读写鼠标设备和键盘也可以达到相同的功能。
页:
[1]