input专题 -- 自动重复

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

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

 

以上就是自动重复的相关分析。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

dianlong_lee

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值