input输入系统中是如何实现按键重复

 看一下 input_dev<include/linux/input.h> 结构体,只列出了和我们讨论的内用有关的成员:

struct input_dev

{

.........

/* stores key code of the last key pressed; used to implement software autorepeat */

unsigned int repeat_key; 

/* timer for software autorepeat */   

struct timer_list timer;

.......

}

接下来我们看一下input_register_device函数,只关心我们讨论的部分:

int input_register_device(struct input_dev *dev)

{

......

init_timer(&dev->timer);

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;

}

......

}

 我么看到该函数初始化了一个内核定时器。input_repeat_key则为按键重复的关键函数,源码如下:

static void input_repeat_key(unsigned long data)

{

struct input_dev *dev = (void *) data;

unsigned long flags;

spin_lock_irqsave(&dev->event_lock, flags);

 

if (test_bit(dev->repeat_key, dev->key) &&

    is_event_supported(dev->repeat_key, dev->keybit, KEY_MAX)) {

/* input_pass_event函数会执行handler中event函数 */

input_pass_event(dev, EV_KEY, dev->repeat_key, 2);

 

if (dev->sync) {

/*

 * Only send SYN_REPORT if we are not in a middle

 * of driver parsing a new hardware packet.

 * Otherwise assume that the driver will send

 * SYN_REPORT once it's done.

 */

input_pass_event(dev, EV_SYN, SYN_REPORT, 1);

}

 

if (dev->rep[REP_PERIOD])

mod_timer(&dev->timer, jiffies +

msecs_to_jiffies(dev->rep[REP_PERIOD]));

}

 

spin_unlock_irqrestore(&dev->event_lock, flags);

}

但是我们没有看到add_timer函数,内核定时器是在什么时候加入内核定时器链表的呢?我们知道在有按键按下是要使用input_report_key函数报告的,看一下该函数:

static inline void input_report_key(struct input_dev *dev, unsigned int code, int value)

{

input_event(dev, EV_KEY, code, !!value);

}

继续往下看:

void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)

{

......

input_handle_event(dev, type, code, value);

......

}

在该函数中我们主要看input_handle_event函数:

static void input_handle_event(struct input_dev *dev,

       unsigned int type, unsigned int code, int value)

{

int disposition = INPUT_IGNORE_EVENT;

switch (type) {

......

case EV_KEY:

if (is_event_supported(code, dev->keybit, KEY_MAX) &&

    !!test_bit(code, dev->key) != value) {

if (value != 2) {

__change_bit(code, dev->key);  /* 每执行该函数就会将该位的值和原来的值进行异或 */

if (value)

input_start_autorepeat(dev, code);

}

 

disposition = INPUT_PASS_TO_HANDLERS;

}

break;

......

 

case EV_REP:

if (code <= REP_MAX && value >= 0 && dev->rep[code] != value) {

dev->rep[code] = value;

disposition = INPUT_PASS_TO_ALL;

}

break;

......

if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN)

dev->sync = 0;

 

if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)

dev->event(dev, type, code, value);

 

if (disposition & INPUT_PASS_TO_HANDLERS)

input_pass_event(dev, type, code, value);

}

我们主要看input_start_autorepeat函数:

static void input_start_autorepeat(struct input_dev *dev, int code)

{

if (test_bit(EV_REP, dev->evbit) &&

dev->rep[REP_PERIOD] && dev->rep[REP_DELAY] &&

dev->timer.data) {

dev->repeat_key = code;

mod_timer(&dev->timer,

jiffies + msecs_to_jiffies(dev->rep[REP_DELAY]));

}

}

我们还是没看到add_timer函数,其实不需要add_timer函数也是可以启动内核定时器的,那就是mod_timer函数,该函数的执行过程等于del_timer(timer); timer->expires = expires; add_timer(timer);所以就会启动内核定时器。

input_report_key的原型如下:

static inline void input_report_key(struct input_dev *dev, unsigned int code, int value);

我们知道在使用input_report_key函数时参数value表示的是按键的按下还是没按下。0表示按键释放,非0表示按键按下。我们看到当按键按下时,如果配置了按键是可以重复的,就会执行input_start_autorepeat函数,该函数就会启动内核定时器,接着就会执行input_repeat_key函数,在该函数中执行:

input_pass_event(dev, EV_KEY, dev->repeat_key, 2);

其中dev->repeat_key保存的为按下按键时的值,我们看到value参数的值为2,在看input_handle_event,该函数中if (value != 2) 里面的语句就不能执行,也就不会执行__change_bit(code, dev->key);所以可以一直执行input_repeat_key中的

if (test_bit(dev->repeat_key, dev->key) &&

    is_event_supported(dev->repeat_key, dev->keybit, KEY_MAX))

里面的语句。执行:

mod_timer(&dev->timer, jiffies +msecs_to_jiffies(dev->rep[REP_PERIOD]));

重启定时器,如此定时器就一直执行下去。

但我们释放按键时。就会改变dev->key的值,使input_repeat_key中的

if (test_bit(dev->repeat_key, dev->key) &&

    is_event_supported(dev->repeat_key, dev->keybit, KEY_MAX))

语句中的内容不能执行了,所以内核定时器也就停止了工作,既停止了按键的重复。

你可能感兴趣的:(linux,input,按键重复)