![如何在不使用鼠标的情况下在 Wayland 中设置绝对鼠标光标位置?](https://linux22.com/image/127185/%E5%A6%82%E4%BD%95%E5%9C%A8%E4%B8%8D%E4%BD%BF%E7%94%A8%E9%BC%A0%E6%A0%87%E7%9A%84%E6%83%85%E5%86%B5%E4%B8%8B%E5%9C%A8%20Wayland%20%E4%B8%AD%E8%AE%BE%E7%BD%AE%E7%BB%9D%E5%AF%B9%E9%BC%A0%E6%A0%87%E5%85%89%E6%A0%87%E4%BD%8D%E7%BD%AE%EF%BC%9F.png)
这个问题很简单。
我在 X 下使用的内容[xdotool]
显然无法继续前进,并且鉴于 Wayland 相对较新的采用,没有出现明显的新解决方案。
需要编程的解决方案是可以接受的。
答案1
您可以使用输入法( linux/uinput.h
)。它适用于 X 和 Wayland。
上面的文档页面有一个示例,其中包括创建一个充当鼠标的虚拟设备:
#include <linux/uinput.h>
void emit(int fd, int type, int code, int val)
{
struct input_event ie;
ie.type = type;
ie.code = code;
ie.value = val;
/* timestamp values below are ignored */
ie.time.tv_sec = 0;
ie.time.tv_usec = 0;
write(fd, &ie, sizeof(ie));
}
int main(void)
{
struct uinput_setup usetup;
int i = 50;
int fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
/* enable mouse button left and relative events */
ioctl(fd, UI_SET_EVBIT, EV_KEY);
ioctl(fd, UI_SET_KEYBIT, BTN_LEFT);
ioctl(fd, UI_SET_EVBIT, EV_REL);
ioctl(fd, UI_SET_RELBIT, REL_X);
ioctl(fd, UI_SET_RELBIT, REL_Y);
memset(&usetup, 0, sizeof(usetup));
usetup.id.bustype = BUS_USB;
usetup.id.vendor = 0x1234; /* sample vendor */
usetup.id.product = 0x5678; /* sample product */
strcpy(usetup.name, "Example device");
ioctl(fd, UI_DEV_SETUP, &usetup);
ioctl(fd, UI_DEV_CREATE);
/*
* On UI_DEV_CREATE the kernel will create the device node for this
* device. We are inserting a pause here so that userspace has time
* to detect, initialize the new device, and can start listening to
* the event, otherwise it will not notice the event we are about
* to send. This pause is only needed in our example code!
*/
sleep(1);
/* Move the mouse diagonally, 5 units per axis */
while (i--) {
emit(fd, EV_REL, REL_X, 5);
emit(fd, EV_REL, REL_Y, 5);
emit(fd, EV_SYN, SYN_REPORT, 0);
usleep(15000);
}
/*
* Give userspace some time to read the events before we destroy the
* device with UI_DEV_DESTOY.
*/
sleep(1);
ioctl(fd, UI_DEV_DESTROY);
close(fd);
return 0;
}
答案2
如果你不想写C代码输入法,有 python 包,甚至一些现有的调试和测试实用程序可以同时工作埃夫德夫level,即
evemu-describe
、evemu-device
、evemu-play
、evemu-record
、 和
evemu-event
来自 evemu 包。您需要成为 root 才能使用它们。下面是一个示例,查找鼠标设备及其生成的事件,然后人为地为其生成事件。
首先我们列出 evdev 设备:
$ sudo evemu-describe
Available devices:
...
/dev/input/event5: Logitech USB Optical Mouse
...
这是一个交互式命令,在列出物理设备后,它要求我们选择一个以获取更多详细信息。 5、鼠标我们选择:
Select the device event number [0-9]: 5
...
# Input device name: "Logitech USB Optical Mouse"
...
# Supported events:
# Event type 0 (EV_SYN)
# Event code 0 (SYN_REPORT)
...
# Event type 1 (EV_KEY)
# Event code 272 (BTN_LEFT)
# Event code 273 (BTN_RIGHT)
# Event code 274 (BTN_MIDDLE)
# Event type 2 (EV_REL)
# Event code 0 (REL_X)
# Event code 1 (REL_Y)
# Event code 8 (REL_WHEEL)
...
另一个 evemu 测试命令将向我们显示移动鼠标时生成的事件:
$ sudo evemu-record /dev/input/event5
E: 4.223 0002 0000 0004 # EV_REL / REL_X 4
E: 4.223 0000 0000 0000 # ------------ SYN_REPORT (0) ------ +8ms
E: 4.231 0002 0000 0007 # EV_REL / REL_X 7
E: 4.231 0002 0001 0001 # EV_REL / REL_Y 1
E: 4.231 0000 0000 0000 # ------------ SYN_REPORT (0) ------ +8ms
通常,对于鼠标移动,存在事件类型 EV_REL、相对移动轴的事件代码 REL_X 和/或 REL_Y,以及移动的事件值距离(上面的 4、7、1)。这些事件之后是 EV_SYN 类型的同步事件,其代码为 SYN_REPORT 以表示事件结束。
我们可以用另一个测试命令注入我们自己的事件(例如移动 20,10):
sudo evemu-event /dev/input/event5 --type EV_REL --code REL_X --value 20
sudo evemu-event /dev/input/event5 --type EV_REL --code REL_Y --value 10 --sync
该--sync
选项将 SYN_REPORT 事件添加到末尾(相当于--type EV_SYN --code SYN_REPORT
)。
最后,另一个测试命令evemu-device
允许我们通过给出描述(例如我们已经看到的鼠标的描述)来创建新的输入设备。它使用/dev/uinput
并创建一个新/dev/input/event*
设备,然后我们可以使用它向其发送事件。
所以即使你没有鼠标,你也可以动态添加一个,然后随心所欲地控制它。我没有具有绝对位置事件的设备来为您提供示例,但您可以类似地添加类似平板电脑的设备并通过它发送绝对移动事件。
答案3
从喵的回答,我写了这个小mousemove
bash 脚本,作为参数运行XREL YREL
。
#!/bin/bash
while IFS=: read dev desc ;do
case $desc in
*[Mm]ouse* ) mousedev=$dev;;
esac
done < <(evemu-describe <<<'' 2>&1)
[ -c "$mousedev" ] &&
evemu-event $mousedev --type EV_REL --code REL_X --value $1 &&
evemu-event $mousedev --type EV_REL --code REL_Y --value $2 --sync
作为root
或通过sudo
:
sudo mousemove -20 10
sudo mousemove -4000 -4000
因为鼠标加速从概念上讲,实际移动并不对应于精确的值,除非非常低的值。