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函數會執行handlerevent函數 */

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))

語句中的內容不能執行了,所以內核定時器也就停止了工作,既停止了按鍵的重複。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章