我需要在weston(wayland)下发送一个虚拟触摸事件。我有一个 1280x800 的屏幕,在 weston.ini 中旋转了 180 度。
我使用 c++ 的 uinput 成功实现了触摸事件仿真:
int fd;
struct uinput_user_dev uidev;
fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
if(fd < 0)
die("error: open");
if(ioctl(fd, UI_SET_EVBIT, EV_KEY) < 0)
die("error: ioctl");
if(ioctl(fd, UI_SET_EVBIT, EV_SYN) < 0)
die("error: ioctl");
if(ioctl(fd, UI_SET_EVBIT, EV_ABS) < 0)
die("error: ioctl");
if(ioctl(fd, UI_SET_ABSBIT, ABS_X) < 0)
die("error: ioctl");
if(ioctl(fd, UI_SET_ABSBIT, ABS_Y) < 0)
die("error: ioctl");
if(ioctl(fd, UI_SET_KEYBIT, BTN_TOUCH) < 0)
die("error: ioctl");
memset(&uidev, 0, sizeof(uidev));
snprintf(uidev.name, UINPUT_MAX_NAME_SIZE, "TestTouch");
uidev.id.bustype = BUS_USB;
uidev.id.vendor = 0x1234;
uidev.id.product = 0x4321;
uidev.id.version = 1;
uidev.absmin[ABS_X] = 0;
uidev.absmax[ABS_X] = 1280;
uidev.absmin[ABS_Y] = 0;
uidev.absmax[ABS_Y] = 800;
ioctl(fd, UI_SET_PROPBIT, INPUT_PROP_DIRECT);
if(write(fd, &uidev, sizeof(uidev)) < 0)
die("error: write");
if(ioctl(fd, UI_DEV_CREATE) < 0)
die("error: ioctl");
sleep(1);
emitEvent(fd, EV_KEY, BTN_TOUCH, 1);
emitEvent(fd, EV_ABS, ABS_X, 100);
emitEvent(fd, EV_ABS, ABS_Y, 100);
emitEvent(fd, EV_SYN, SYN_REPORT, 0);
usleep(300);
emitEvent(fd, EV_KEY, BTN_TOUCH, 0);
emitEvent(fd, EV_SYN, SYN_REPORT, 0);
sleep(1);
if(ioctl(fd, UI_DEV_DESTROY) < 0)
die("error: ioctl");
我在 X:100, Y:100 发送触摸事件。该事件在韦斯顿中正确注册(我使用的是一个简单的网站,它在屏幕上跟踪鼠标事件)但不是在左上角,而是在右下角。就在屏幕的原始 (100,100) 坐标所在的位置 - 因为它旋转了 180 度(这是我无法更改的硬件限制,需要旋转屏幕才能适应外壳)。
我尝试了INPUT_PROP_DIRECT
orINPUT_PROP_POINTER
但没有任何变化的各种组合。
为了使事件在正确的坐标,我需要转换它们:
x = (1280 - x); y = (800 - y);
但我想让它适用于任何类型的屏幕或旋转。我很惊讶,因为我确信是合成器扮演了转换输入事件的角色。在寻找类似问题时,我偶然发现了这些信息:
wlr_cursor probably needs to transform input events. This is already done in the Wayland and X11 backends, we might want to move it in wlr_cursor.