...
经过编译安装后,注销重新登录。开始对Xorg进行gdb调试分析。
首先对xserver源码进行了初步的阅读分析,对GetKeyboardEvents进行断点调试。
正常按下抬起Ctrl按键时,调用栈信息打印如下:
代码块 |
---|
Ctrl按键按下时的调用栈信息:
Thread 18 "InputThread" hit Breakpoint 3, GetKeyboardEvents (events=0x7f95242010, pDev=pDev@entry=0x559f0848b0, type=type@entry=2, key_code=key_code@entry=37) at ../../dix/getevents.c:1067
1067 {
(gdb) bt
#0 GetKeyboardEvents (events=0x7f95242010, pDev=pDev@entry=0x559f0848b0, type=type@entry=2, key_code=key_code@entry=37) at ../../dix/getevents.c:1067
#1 0x0000005579ac9d74 in QueueKeyboardEvents (device=device@entry=0x559f0848b0, type=type@entry=2, keycode=keycode@entry=37) at ../../dix/getevents.c:1051
#2 0x0000005579afab30 in xf86PostKeyEventM (device=device@entry=0x559f0848b0, key_code=key_code@entry=37, is_down=is_down@entry=1) at ../../../../hw/xfree86/common/xf86Xinput.c:1423
#3 0x0000005579afab9c in xf86PostKeyboardEvent (device=0x559f0848b0, key_code=37, is_down=1) at ../../../../hw/xfree86/common/xf86Xinput.c:1432
#4 0x0000007f82381e14 in () at /usr/lib/xorg/modules/input/libinput_drv.so
#5 0x0000007f823829e4 in () at /usr/lib/xorg/modules/input/libinput_drv.so
#6 0x0000005579bfb22c in InputReady (fd=24, xevents=1, data=0x559ee27cf0) at ../../os/inputthread.c:180
#7 0x0000005579bfd940 in ospoll_wait (ospoll=0x559eb9ce30, timeout=timeout@entry=-1) at ../../os/ospoll.c:657
#8 0x0000005579bfb078 in InputThreadDoWork (arg=<optimized out>) at ../../os/inputthread.c:369
#9 0x0000007f957c651c in start_thread (arg=0x7fec380d4f) at pthread_create.c:477
#10 0x0000007f9571d88c in thread_start () at ../sysdeps/unix/sysv/linux/aarch64/clone.S:78
Ctrl按键抬起时的调用栈信息:
Thread 18 "InputThread" hit Breakpoint 3, GetKeyboardEvents (events=0x7f95242010, pDev=pDev@entry=0x559f0848b0, type=type@entry=3, key_code=key_code@entry=37) at ../../dix/getevents.c:1067
1067 {
(gdb) bt
#0 GetKeyboardEvents (events=0x7f95242010, pDev=pDev@entry=0x559f0848b0, type=type@entry=3, key_code=key_code@entry=37) at ../../dix/getevents.c:1067
#1 0x0000005579ac9d74 in QueueKeyboardEvents (device=device@entry=0x559f0848b0, type=type@entry=3, keycode=keycode@entry=37) at ../../dix/getevents.c:1051
#2 0x0000005579afab30 in xf86PostKeyEventM (device=device@entry=0x559f0848b0, key_code=key_code@entry=37, is_down=is_down@entry=0) at ../../../../hw/xfree86/common/xf86Xinput.c:1423
#3 0x0000005579afab9c in xf86PostKeyboardEvent (device=0x559f0848b0, key_code=37, is_down=0) at ../../../../hw/xfree86/common/xf86Xinput.c:1432
#4 0x0000007f82381e14 in () at /usr/lib/xorg/modules/input/libinput_drv.so
#5 0x0000007f823829e4 in () at /usr/lib/xorg/modules/input/libinput_drv.so
#6 0x0000005579bfb22c in InputReady (fd=24, xevents=1, data=0x559ee27cf0) at ../../os/inputthread.c:180
#7 0x0000005579bfd940 in ospoll_wait (ospoll=0x559eb9ce30, timeout=timeout@entry=-1) at ../../os/ospoll.c:657
#8 0x0000005579bfb078 in InputThreadDoWork (arg=<optimized out>) at ../../os/inputthread.c:369
#9 0x0000007f957c651c in start_thread (arg=0x7fec380d4f) at pthread_create.c:477
#10 0x0000007f9571d88c in thread_start () at ../sysdeps/unix/sysv/linux/aarch64/clone.S:78 |
按住Ctrl按键,然后滚动鼠标滚轮时的调用栈信息如下:
代码块 |
---|
Thread 1 "X" hit Breakpoint 3, GetKeyboardEvents (events=0x7f94d4f010, pDev=0x559eba1450, type=type@entry=2, key_code=37) at ../../dix/getevents.c:1067
1067 {
(gdb) bt
#0 GetKeyboardEvents (events=0x7f94d4f010, pDev=0x559eba1450, type=type@entry=2, key_code=37) at ../../dix/getevents.c:1067
#1 0x0000005579b439bc in ProcXTestFakeInput (client=0x559f0c84b0) at ../../Xext/xtest.c:423
#2 0x0000005579ab23e0 in Dispatch () at ../../dix/dispatch.c:478
#3 0x0000005579ab650c in dix_main (argc=11, argv=0x7fec380fe8, envp=<optimized out>) at ../../dix/main.c:276
#4 0x0000007f9566cd90 in __libc_start_main (main=
0x5579a9ff30 <main>, argc=11, argv=0x7fec380fe8, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=<optimized out>) at ../csu/libc-start.c:308
#5 0x0000005579a9ff68 in _start () at ../../Xext/xtest.c:538 |
对比上面两种情况下,GetKeyboardEvents的调用栈信息发现,在异常情况下走的是ProcXTestFakeInput流程。会产生额外的模拟输入事件。修改xtest.c文件进行测试验证,在ProcXTestFakeInput函数中,将type为KeyPress和KeyRelease的event直接return掉。
测试操作x11窗口,按住Ctrl按键滚动鼠标滚轮时没有再收到Ctrl按键抬起事件。结果说明xserver确实有向Client端发送额外的模拟输入事件。接下来分析排查xserver处理的键盘模拟输入事件的发送方到底是谁。
继续gdb调试Xorg进程,在ProcXTestFakeInput函数设置断点,按住Ctrl按键滚动鼠标滚轮复现问题。
调试分析结果如下图所示:
...
这里找到了Ctrl按键up伪事件的来源为imwheel程序。imwheel进程使用XTEST扩展Xorg发送模拟事件。包名为imwheel,程序路径/usr/bin/imwheel。将imwheel进程kill掉测试验证结果:按住Ctrl按键滚动鼠标滚轮x11窗口不再重复收到Ctrl按键抬起事件。测试weston应用方式启动的OpenFDE鼠标滚轮模拟双指触摸缩放功能恢复正常。
6、imwheel分析研究
imwheel:是在Linux中支持鼠标非标准按钮的一个程序,用于Linux系统的鼠标滚轮增强工具,它可以重新映射滚轮事件,以提供更好的滚动控制和自定义功能,如缩放、翻页等。事件传递流程如下图所示。
...
最后通过对imwheel项目源码及配置文件的分析,可以通过imwheel -k -b "0 0 0 0 8 9"命令跳过鼠标滚轮抓取。修改fde_ctrl项目的fde_utils文件,在OpenFDE的启动脚本中增加上面的imwheel设置命令。
...