Linux 的 Input Device 是重要的一个 subsystem,在进行实例介绍前,先大略了解一下相关的 API。
Linux Input Device
input.c是Linux的"input"驱动程式,主要支援键盘与滑鼠的输入;input.c介面有趣的地方是采用了事件(event)的方式来处理输入,以下是input.c介面重要的资料结构与函数:
* struct input_dev
* void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
* void input_register_device(struct input_dev *);
* void input_unregister_device(struct input_dev *);
* void input_register_handler(struct input_handler *);
* void input_unregister_handler(struct input_handler *);
Linux 的input机制可用来实作「虚拟键盘」或「虚拟滑鼠」,只要呼叫input_event()将输入资料发布给input handler即可。
struct input_dev是用来描述输入事件的重要资料结构,其原型宣告如下: struct input_dev {
void *private; int number;
char *name;
unsigned short idbus;
unsigned short idvendor;
unsigned short idproduct;
unsigned short idversion; unsigned long evbit[NBITS(EV_MAX)];
unsigned long keybit[NBITS(KEY_MAX)];
unsigned long relbit[NBITS(REL_MAX)];
unsigned long absbit[NBITS(ABS_MAX)];
unsigned long mscbit[NBITS(MSC_MAX)];
unsigned long ledbit[NBITS(LED_MAX)];
unsigned long sndbit[NBITS(SND_MAX)];
unsigned long ffbit[NBITS(FF_MAX)];
int ff_effects_max; unsigned int keycodemax;
unsigned int keycodesize;
void *keycode; unsigned int repeat_key;
struct timer_list timer; int abs[ABS_MAX + 1];
int rep[REP_MAX + 1]; unsigned long key[NBITS(KEY_MAX)];
unsigned long led[NBITS(LED_MAX)];
unsigned long snd[NBITS(SND_MAX)]; int absmax[ABS_MAX + 1];
int absmin[ABS_MAX + 1];
int absfuzz[ABS_MAX + 1];
int absflat[ABS_MAX + 1]; int (*open)(struct input_dev *dev);
void (*close)(struct input_dev *dev);
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 *handle;
struct input_dev *next;
}; 定义按键
我们可以设定struct input_dev里的evbit栏位,来定义所要接受的输入类型,目前共有8种输入类型如下:
* EV_KEY:Keys and buttons(按键与按钮)。
* EV_REL:Relative axes(相对座标)。
* EV_ABS:Absolute axes(绝对座标)。
* EV_MSC:Misc events(其它事件)。
* EV_LED:LEDs。
* EV_SND:Sounds(声音输入)。
* EV_REP:Autorepeat values(自动重覆数值)。
* EV_FF:Force feedback事件。
以下是一个范例,我们指定dev可接受EV_KEY事件:
dev.evbit[0] = BIT(EV_KEY);
evbit是一个阵列,每个元素可以索引一种输入类型。每种输入类型均可指定特定的输入资料,例如:TAB键。指定方式是使用set_bit()或BIT巨集来设定每种输入类型的阵列。以下是各输入类型的栏位名称:
* keybit[NBITS(KEY_MAX)]:Keys and buttons(按键与按钮)。
* relbit[NBITS(REL_MAX)]:Relative axes(相对座标)。
* absbit[NBITS(ABS_MAX)]:Absolute axes(绝对座标)。
* mscbit[NBITS(MSC_MAX)]:Misc events(其它事件)。
* ledbit[NBITS(LED_MAX)]:LEDs。
* sndbit[NBITS(SND_MAX)]:Sounds(声音输入)。
* ffbit[NBITS(FF_MAX)]:Force feedback事件。
以下是使用set_bit()的范例:
* set_bit(KEY_UP, dev.keybit);
* set_bit(KEY_LEFT, dev.keybit);
或是使用BIT巨集也可以:
* keybit[0] = BIT(KEYUP) | BIT(KEY_LEFT);
input.h里做位元运算的3个巨集如下:
* NBITS(x):计算要几个阵列元素,才够纪录第x个位元。
* BIT(x):传回单独第x个位元为1时所代表的数值,例如:x=0时为0x1,x=1时为0x2,x=2时为0x4。
* LONG(x):第x个位元是属於第几个阵列元素(即索引值)。
我们先设定驱动程式能接受EV_KEY事件,然后指定EV_KEY事件的特定输入值为KEY_UP与KEY_LEFT按键。不同事件的输入资料定义,请参考input.h档,例如以下是EV_KEY事件的按键1~按键9定义:
/*
* Keys and buttons
*/
#define KEY_1 2
#define KEY_2 3
#define KEY_3 4
#define KEY_4 5
#define KEY_5 6
#define KEY_6 7
#define KEY_7 8
#define KEY_8 9
#define KEY_9 10
设定好struct input_dev后再呼叫input_register_device()注册至上层。当"input device"注册至kernel后,当该input device被开启时,便呼叫input device的open method;当input device关闭时,便呼叫input device的close method。
Report 按键
使用者的按键往上层回报所使用的API如下:
* input_report_key(struct input_dev *dev, unsigned int code, int value);
* input_report_rel(struct input_dev *dev, unsigned int code, int value);
* input_report_abs(struct input_dev *dev, unsigned int code, int value);
* input_report_key与input_report_rel其实都是使用input_event()的巨集,input_event()的函数原型与参数说明如下:
* void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value);
* @dev:指向input device的指标。
* @type:输入类型(EV_KEY、EV_ABS等)。
* @code:输入按键(例如EV_KEY的KEY_1)。
* @value:按键值。
Input Handler
任何的按键输入,都应呼叫input_event()来将input event送到input.c,再由input.c分派事件(遶送)到每一个"input handler"。有注册input handler的驱动程式,都能读取输入资料。 --jollen