免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 5896 | 回复: 1

分享一个linux下用键盘模拟鼠标的驱动 [复制链接]

论坛徽章:
0
发表于 2011-06-19 22:48 |显示全部楼层
用小键盘的上下左右控制鼠标,小键盘数字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[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
        vms->dev->keybit[BIT_WORD(BTN_LEFT)] = BIT_MASK(BTN_LEFT);
        vms->dev->relbit[0] = 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

论坛徽章:
0
发表于 2011-06-25 00:19 |显示全部楼层
Good!    从功能上来说,在用户空间直接读写鼠标设备和键盘也可以达到相同的功能。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

DTCC2020中国数据库技术大会

【架构革新 高效可控】2020年12月21日-23日第十一届中国数据库技术大会将在北京隆重召开。

大会设置2大主会场,20+技术专场,将邀请超百位行业专家,重点围绕数据架构、AI与大数据、传统企业数据库实践和国产开源数据库等内容展开分享和探讨,为广大数据领域从业人士提供一场年度盛会和交流平台。

http://dtcc.it168.com


大会官网>>
  

北京盛拓优讯信息技术有限公司. 版权所有 16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122
中国互联网协会会员  联系我们:huangweiwei@it168.com
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP