1. 問題:
linux平臺下,按鍵應用處於忙狀態,此時頻繁按下按鍵,出現按鍵事件丟失等異常現象?
2. 原因:
按鍵緩衝區是一個環狀緩衝區,如果插入事件導致head與tail相等,即可判定緩衝區發生了溢出,會丟棄緩衝區中的所有事件,同時內核會向緩衝區放入一個SYN_DROPPED事件,通知用戶程序事件有丟失。
3. 解決:
由於內核input子系統上報的是按下和擡起事件,內核清空緩衝隊列後可能會出現只上報單個擡起或者按下事件要注意處理。本次發現問題就是因爲系統只上報按下事件沒有擡起事件導致應用觸發了長按事件。
當收到SYN_DROPPED事件時:
- 清除按鍵保存的狀態
- 忽略掉第一次就出現的擡起事件
- 忽略掉重複的按鍵事件(按鍵事件正常應該是按下、擡起成對出現的)
4. 內核代碼
kernel/drivers/input/evdev.c
static void __pass_event(struct evdev_client *client,
const struct input_event *event)
{
...
if (unlikely(client->head == client->tail)) {
/*
* This effectively "drops" all unconsumed events, leaving
* EV_SYN/SYN_DROPPED plus the newest event in the queue.
*/
client->tail = (client->head - 2) & (client->bufsize - 1);
client->buffer[client->tail].time = event->time;
client->buffer[client->tail].type = EV_SYN;
client->buffer[client->tail].code = SYN_DROPPED;
client->buffer[client->tail].value = 0;
client->packet_head = client->tail;
if (client->use_wake_lock)
wake_unlock(&client->wake_lock);
}
...
}