input要实现自动重复,首先要支持事件EV_REP

自动上报的流程如下:

input_event() ->input_handle_event() ->input_pass_values()

static void input_pass_values(struct input_dev *dev,
			      struct input_value *vals, unsigned int count)
{
	struct input_handle *handle;
	struct input_value *v;
	if (!count)
		return;
	rcu_read_lock();
	handle = rcu_dereference(dev->grab);
	if (handle) {
		count = input_to_handler(handle, vals, count);
	} else {
		list_for_each_entry_rcu(handle, &dev->h_list, d_node)
			if (handle->open) {
				count = input_to_handler(handle, vals, count);
				if (!count)
					break;
			}
	}
	rcu_read_unlock();
	/* trigger auto repeat for key events */
	if (test_bit(EV_REP, dev->evbit) && test_bit(EV_KEY, dev->evbit)) {
		for (v = vals; v != vals + count; v++) {
			if (v->type == EV_KEY && v->value != 2) {
				if (v->value)
					input_start_autorepeat(dev, v->code);
				else
					input_stop_autorepeat(dev);
			}
		}
	}

可以看到这个函数分两部分,第一部分上报事件,第二部分上报重复事件。

对于自动重复,首先判断是否支持事件EV_REP,这是前提,再一个就是要支持EV_KEY,因为自动重复是设计给key事件的,比如长按按键,就会一直上报。

对于EV_KEY,value为1表示按下,value为0表示松开。

也就是说,当前上报的是按键按下的事件,那么就会启动自动重复,也就是执行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.function) {
		dev->repeat_key = code;
		mod_timer(&dev->timer,
			  jiffies + msecs_to_jiffies(dev->rep[REP_DELAY]));
	}
}

可以看到再次判断是否支持EV_REP,这里REP_PERIOD和REP_DELAY代表的含义如下

比如一个键被按下,3秒之后如果还是按下就是算重复按键,事件上报,之后每隔1秒重复上报

这个3秒就是rep[REP_DELAY]

这个1秒就是rep[REP_PERIOD]

这里会把键值放到repeat_key里面保存,然后会启动一个定时器,那么这2个时间和定时器处理函数在哪里定义呢?

在input_register_device中

int input_register_device(struct input_dev *dev)
{
    ...
	/*
	 * If delay and period are pre-set by the driver, then autorepeating
	 * is handled by the driver itself and we don't do it in input.c.
	 */
	if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD])
		input_enable_softrepeat(dev, 250, 33);
    ...
}

注册input设备的时候,会去检测驱动中是否设置了rep[REP_DELAY]和rep[REP_PERIOD](单位是毫秒),如果没有设置则会使能软件自动重复,其实就是设置这2个时间以及添加定时器处理函数

void input_enable_softrepeat(struct input_dev *dev, int delay, int period)
{
	dev->timer.function = input_repeat_key;
	dev->rep[REP_DELAY] = delay;
	dev->rep[REP_PERIOD] = period;
}

也就是说,如果驱动代码中设置了2个时间,那么必须也加上自己的定时器处理函数,如果没有的话,则无法开启自动重复功能。

我们看一下默认的定时器处理函数

input_repeat_key()

static void input_repeat_key(struct timer_list *t)
{
	struct input_dev *dev = from_timer(dev, t, timer);
	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)) {
		struct input_value vals[] =  {
			{ EV_KEY, dev->repeat_key, 2 },
			input_value_sync
		};
		input_pass_values(dev, vals, ARRAY_SIZE(vals));
		if (dev->rep[REP_PERIOD])
			mod_timer(&dev->timer, jiffies +
					msecs_to_jiffies(dev->rep[REP_PERIOD]));
	}
	spin_unlock_irqrestore(&dev->event_lock, flags);
}

可以看到这里会上报EV_KEY和EV_SYN 2个事件,然后又启动定时器,定时时间rep[PER_PERIOD]毫秒。这样就出现了rep[PER_PERIOD]毫秒间隔的按键重复上报。

注意这里按键事件上报的时候,出现了value值为2

这也就是在input_get_disposition中。为什么有这样判断value是否为2的代码

	case EV_KEY:
		if (is_event_supported(code, dev->keybit, KEY_MAX)) {
			/* auto-repeat bypasses state updates */
			if (value == 2) {
				disposition = INPUT_PASS_TO_HANDLERS;
				break;
			}
			if (!!test_bit(code, dev->key) != !!value) {
				__change_bit(code, dev->key);
				disposition = INPUT_PASS_TO_HANDLERS;
			}
		}
		break;

还有一方面就是防止再次启动自动重复

​
static void input_pass_values(struct input_dev *dev,
			      struct input_value *vals, unsigned int count)
{
	...
	/* trigger auto repeat for key events */
	if (test_bit(EV_REP, dev->evbit) && test_bit(EV_KEY, dev->evbit)) {
		for (v = vals; v != vals + count; v++) {
			if (v->type == EV_KEY && v->value != 2) {
				if (v->value)
					input_start_autorepeat(dev, v->code);
				else
					input_stop_autorepeat(dev);
			}
		}
	}
​

因为只有value非2的时候才会启动自动重复。

那么当按键放开,自动重复是如何停止的呢?

按键放开,就会产生新的事件,事件value值为0,就会执行下面的 input_stop_autorepeat

static void input_stop_autorepeat(struct input_dev *dev)
{
	del_timer(&dev->timer);
}

可以看到就是简单的停止计时器。


本文由转载于互联网,如有侵权请联系删除!