Linux下如何模拟touch事件?

12 篇文章 0 订阅
7 篇文章 0 订阅

试验一:

Device:Beagle Board

System:Android GingerBread2.3.4

首先找出单击左键对应的events,将Beagle Board通过串口连至主机,并在主机串口输入如下命令:
getevent

然后Beagle Board Android里鼠标点击左键动作,主机串口产生输出如下:
# Click the right-bottom corner:
/dev/input/event2: 0004 0004 00090001
/dev/input/event2: 0001 0110 00000001
/dev/input/event2: 0000 0000 00000000
/dev/input/event2: 0004 0004 00090001
/dev/input/event2: 0001 0110 00000000
/dev/input/event2: 0000 0000 00000000

# Click somewhere:
/dev/input/event2: 0004 0004 00090001
/dev/input/event2: 0001 0110 00000001
/dev/input/event2: 0000 0000 00000000
/dev/input/event2: 0004 0004 00090001
/dev/input/event2: 0001 0110 00000000
/dev/input/event2: 0000 0000 00000000

然后试验由主机串口发出相同的events,看看是否会产生同样的动作?
将鼠标置于Beagle Board屏幕左下角或右下角的翻屏指示处(发出的events预期产生click动作,但是位置坐标还得由鼠标选定),主机串口输入如下命令:
sendevent /dev/input/event2 4 4 589825
sendevent /dev/input/event2 1 272 1
sendevent /dev/input/event2 0 0 0
sendevent /dev/input/event2 4 4 589825
sendevent /dev/input/event2 1 272 0
sendevent /dev/input/event2 0 0 0

Beagle Board Android没反应,说明系统有问题!



试验二:

Device:Beagle Board

System:Android GingerBread2.3.4


修改Beagle Board Android源代码,即修改文件

/home/tomxue/Tom/Source_Code/Android/rowboat-android/TI_Android_GingerBread_2_3_4Sources/kernel/drivers/input/evdev.c

如下:
--- evdev.c    2012-09-20 20:41:56.623617427 +0800
+++ evdev_modified.c    2012-09-20 20:42:37.872802833 +0800
@@ -347,8 +347,9 @@
             goto out;
         }
 
-        input_inject_event(&evdev->handle,
-                   event.type, event.code, event.value);
+        printk("Tom Xue position 1...................................");
+        evdev_event(&evdev->handle,event.type, event.code, event.value);
+        
         retval += input_event_size();
     }

然后,重新编译kernel,用生成的uImage替换SD卡内的uImage,重启(注意要设置bootargs参数,再reset)
再做上面的试验一,这次,events从主机串口发送之后,Beagle Board Android界面上可以看出,屏幕被切换了!试验成功!



接下来探讨一下深层原因...

先把上面的改动(evdev.c)复原,然后在kernel代码中插入一些打印函数如下:
--- input.c    2012-09-20 19:54:55.571647181 +0800
+++ input-modified.c    2012-09-20 19:53:57.098325853 +0800
@@ -332,11 +332,15 @@
     if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN)
         dev->sync = false;
 
-    if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)
+    if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event) {
+        printk("input_handle_event INPUT_PASS_TO_DEVICE\n");
         dev->event(dev, type, code, value);
+    }
 
-    if (disposition & INPUT_PASS_TO_HANDLERS)
+    if (disposition & INPUT_PASS_TO_HANDLERS) {
+        printk("input_handle_event INPUT_PASS_TO_HANDLERS\n");
         input_pass_event(dev, src_handler, type, code, value);
+    }
 }
 
 /**
@@ -389,15 +393,20 @@
     struct input_handle *grab;
     unsigned long flags;
     
+    printk(KERN_INFO "the device name is %s", dev->name);
+    printk(KERN_INFO "input_inject_event position 1\n");
+
     if (is_event_supported(type, dev->evbit, EV_MAX)) {
+    printk(KERN_INFO "input_inject_event position 2\n");
         spin_lock_irqsave(&dev->event_lock, flags);
 
         rcu_read_lock();
         grab = rcu_dereference(dev->grab);
-        if (!grab || grab == handle)
+        if (!grab || grab == handle) {
+            printk(KERN_INFO "input_inject_event position 3\n");
             input_handle_event(dev, handle->handler,
                        type, code, value);
-
+        }
         rcu_read_unlock();
 
         spin_unlock_irqrestore(&dev->event_lock, flags);


还有头文件drivers/input/input.h中,增加printk输出
static inline void input_sync(struct input_dev *dev)
{
    input_event(dev, EV_SYN, SYN_REPORT, 0);
        printk("to verify that input_sync is called instead\n");
}


然后,在Beagle Board Android屏幕上任意位置点击鼠标左键,可以在主机串口中看到getevent的输出如下:
# input_handle_event INPUT_PASS_TO_DEVICE
input_handle_event INPUT_PASS_TO_HANDLERS
input_handle_event INPUT_PASS_TO_HANDLERS
input_handle_event INPUT_PASS_TO_HANDLERS
to verify that input_sync is called instead
input_handle_event INPUT_PASS_TO_DEVICE
input_handle_event INPUT_PASS_TO_HANDLERS
input_handle_event INPUT_PASS_TO_HANDLERS
input_handle_event INPUT_PASS_TO_HANDLERS
to verify that input_sync is called instead


根据代码的改动(printk输出)分析一下,可以确定 “ 实际鼠标动作” 调用函数顺序如下:
input_handle_event
input_sync
input_handle_event
input_sync


将鼠标置于左下角或右下角的翻屏指示处,主机串口输入如下命令(做 “ 模拟鼠标动作”):
sendevent /dev/input/event2 4 4 589825
sendevent /dev/input/event2 1 272 1
sendevent /dev/input/event2 0 0 0
sendevent /dev/input/event2 4 4 589825
sendevent /dev/input/event2 1 272 0
sendevent /dev/input/event2 0 0 0


然后,查看Beagle Board的dmesg打印输出如下:
# sendevent /dev/input/event2 4 4 589825
event2 1 272 0
sendevent /dev/input/event2 0 0 0the device name is USB Optical Mouse
input_inject_event position 1
input_inject_event position 2
input_inject_event position 3
input_handle_event INPUT_PASS_TO_DEVICE
input_handle_event INPUT_PASS_TO_HANDLERS
# sendevent /dev/input/event2 1 272 1

the device name is USB Optical Mouse
input_inject_event position 1
input_inject_event position 2
input_inject_event position 3
input_handle_event INPUT_PASS_TO_HANDLERS
# sendevent /dev/input/event2 0 0 0
the device name is USB Optical Mouse
input_inject_event position 1
input_inject_event position 2
input_inject_event position 3
input_handle_event INPUT_PASS_TO_HANDLERS
# sendevent /dev/input/event2 4 4 589825
the device name is USB Optical Mouse
input_inject_event position 1
input_inject_event position 2
input_inject_event position 3
input_handle_event INPUT_PASS_TO_DEVICE
input_handle_event INPUT_PASS_TO_HANDLERS
# sendevent /dev/input/event2 1 272 0
the device name is USB Optical Mouse
input_inject_event position 1
input_inject_event position 2
input_inject_event position 3
input_handle_event INPUT_PASS_TO_HANDLERS
# sendevent /dev/input/event2 0 0 0
the device name is USB Optical Mouse
input_inject_event position 1
input_inject_event position 2
input_inject_event position 3
input_handle_event INPUT_PASS_TO_HANDLERS
以上调试信息说明input_inject_event()和它所调用的函数input_handle_event()都得到了完全执行,也即把event传递给了handler

根据代码的改动(printk输出)分析一下, 模拟鼠标动作的函数调用顺序如下:

input_inject_event->input_handle_event->input_pass_event->(handle->handler->event)

而这个event通常就应该是evdev_event()函数(但貌似GingerBread2.3.4不是这样的,或者函数调用出错)


可见,对比 实际鼠标动作,它 缺少的是input_sync()调用
static inline void input_sync(struct input_dev *dev)
{
    input_event(dev, EV_SYN, SYN_REPORT, 0);
}


那么把input_inject_event()替换成evdev_event()为什么成功了呢?
看看下面的函数调用即可知,evdev_event()中通过kill_fasync()将EV_SYN事件通知了用户空间进程,由后者完成对EV_SYN的处理

evdev_event->evdev_pass_event->
        do {
            client->buffer[client->head++] = *event;
            client->head &= client->bufsize - 1;
        } while (client->head == client->tail);
        ...
        if (event->type == EV_SYN)
            kill_fasync(&client->fasync, SIGIO, POLL_IN);

其实evdev_event()的重点在于将event放入buffer中,这个buffer定义为evdev_client的input_event[]数组;

而evdev_read()函数将会把该buffer中的event传至用户空间,进而触发相应的动作


结论:

从以上分析可知,Beagle Board Android GingerBread2.3.4下的模拟鼠标动作最终没能成功调用evdev_event()函数,导致其无法报告EV_SYN事件,进而失败。




试验三:

Device:HTC Android phone

System:Android GingerBread4.0.3


主机串口试图捕获触摸动作产生的events:
tomxue@ubuntu:~$ adb shell getevent
add device 1: /dev/input/event5
  name:     "proximity"
add device 2: /dev/input/event4
  name:     "lightsensor-level"
add device 3: /dev/input/event3
  name:     "pyramid-keypad"
add device 4: /dev/input/event2
  name:     "cy8c-touchscreen"
add device 5: /dev/input/event1
  name:     "rcp_events"
add device 6: /dev/input/event0
  name:     "h2w headset"
/dev/input/event2: 0003 0030 00000032
/dev/input/event2: 0003 0032 00000032
/dev/input/event2: 0003 003a 00000032
/dev/input/event2: 0003 0035 000003a5
/dev/input/event2: 0003 0036 00000378
/dev/input/event2: 0000 0002 00000000
/dev/input/event2: 0001 014a 00000001
/dev/input/event2: 0000 0000 00000000
/dev/input/event2: 0003 0030 0000000d
/dev/input/event2: 0003 0032 0000000d
/dev/input/event2: 0003 003a 0000000d
/dev/input/event2: 0003 0035 0000039f
/dev/input/event2: 0003 0036 0000037c
/dev/input/event2: 0000 0002 00000000
/dev/input/event2: 0000 0000 00000000
/dev/input/event2: 0000 0002 00000000
/dev/input/event2: 0001 014a 00000000
/dev/input/event2: 0000 0000 00000000

# click again on the right-bottom corner: (App Evernote is there)
/dev/input/event2: 0003 0030 0000002d
/dev/input/event2: 0003 0032 0000002d
/dev/input/event2: 0003 003a 0000002d
/dev/input/event2: 0003 0035 000003a4
/dev/input/event2: 0003 0036 00000386
/dev/input/event2: 0000 0002 00000000
/dev/input/event2: 0001 014a 00000001
/dev/input/event2: 0000 0000 00000000
/dev/input/event2: 0003 0030 0000002d
/dev/input/event2: 0003 0032 0000002d
/dev/input/event2: 0003 003a 0000002d
/dev/input/event2: 0003 0035 000003a5
/dev/input/event2: 0003 0036 00000386
/dev/input/event2: 0000 0002 00000000
/dev/input/event2: 0000 0000 00000000
/dev/input/event2: 0000 0002 00000000
/dev/input/event2: 0001 014a 00000000
/dev/input/event2: 0000 0000 00000000

于是 模拟触摸事件的script被写成这样:
adb shell sendevent /dev/input/event2 3 48 51
adb shell sendevent /dev/input/event2 3 50 51
adb shell sendevent /dev/input/event2 3 58 51
adb shell sendevent /dev/input/event2 3 53 937
adb shell sendevent /dev/input/event2 3 54 913
adb shell sendevent /dev/input/event2 0 2 0
adb shell sendevent /dev/input/event2 1 330 1
adb shell sendevent /dev/input/event2 0 0 0
adb shell sendevent /dev/input/event2 3 48 51
adb shell sendevent /dev/input/event2 3 50 51
adb shell sendevent /dev/input/event2 3 58 51
adb shell sendevent /dev/input/event2 3 53 937
adb shell sendevent /dev/input/event2 3 54 913
adb shell sendevent /dev/input/event2 0 2 0
adb shell sendevent /dev/input/event2 0 0 0
adb shell sendevent /dev/input/event2 0 2 0
adb shell sendevent /dev/input/event2 1 330 0
adb shell sendevent /dev/input/event2 0 0 0

通过主机串口下执行:
./script

发现HTC Android phone上的Evernote图标出现的不是单击效果,而是 缓慢单击的效果:不是打开应用,而是询问是否要拖动后删除它...
猜测是否上述的脚本命令执行效率的问题?将上面的script前面的adb shell字样去掉,将其传至HTC phone /data目录下,执行,以为效率提高会导致不一样的结果,可是结果还是一样的...




结论:


那么试验三表明HTC Android phone至少可以响应模拟触摸事件

而试验一和试验二显示Beagle Board Android GingerBread2.3.4必须改动源码才能正确响应模拟鼠标动作





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值