计算鼠标按钮 X11 Linux

问题描述 投票:0回答:1

这是我的第一个问题,但我真的很迷茫,我需要你的帮助。我正在用 C 编写一个程序,打印出鼠标按钮的数量。我决定使用 XI.h 来解决这个问题。该程序的行为很奇怪。

所提供的代码是一个较大程序的代码,这就是包含如此多库的原因。只是别看它。

使用的来源: XListInputDevices XInternAtom

程序代码(mouse.c)

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/extensions/Xfixes.h>
#include <X11/extensions/XInput.h>
#include <X11/extensions/XI.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h> /* socket() connect() bind() listen() accept() socketpair() */
#include <sys/types.h>
#include <unistd.h> 
#include <string.h> /* strcpy() */
#include <stdio.h> /* perror() */
#include <errno.h> /* error numbers */
#include <stdlib.h>

int main ( void )
{
    XDeviceInfo mouse_info;
    XDeviceInfoPtr ptr_mouse_info;
    XDevice *mouse;
    XID mouse_id;
    XButtonInfoPtr ptr_mouse_buttons;
    XKeyInfoPtr ptr_mouse_keys;
    XValuatorInfoPtr ptr_mouse_axes;
    char * mouse_name;
    int num_devices, num_props, i;
    Display *display = XOpenDisplay(NULL);
    if (display == NULL)
    {
        perror("XOpenDisplay error");
        exit(-1);
    }
    
    ptr_mouse_info = XListInputDevices(display, &num_devices);
    for (i = 0; i < num_devices; i++)
    {
        if (XInternAtom(display, XI_MOUSE, 1) == ptr_mouse_info[i].type)
        {
            mouse_id=ptr_mouse_info[i].id;
            mouse_name=ptr_mouse_info[i].name;
            mouse = XOpenDevice(display, mouse_id);
            
            ptr_mouse_buttons = (XButtonInfoPtr)&ptr_mouse_info[i].inputclassinfo[ButtonClass];
            ptr_mouse_keys = (XKeyInfoPtr) &ptr_mouse_info[i].inputclassinfo[KeyClass];
            printf("Mouse name: %s\n", mouse_name);
            printf("Number of buttons: %d\n", ptr_mouse_buttons->num_buttons);
            printf("Number of keys: %d\n", ptr_mouse_keys->num_keys);
        }
    }
    printf("Mouse name: %s\n", mouse_name);
    printf("Number of buttons: %d\n", ptr_mouse_buttons->num_buttons);
    printf("Number of keys: %d\n", ptr_mouse_keys->num_keys);
    XFreeDeviceList(ptr_mouse_info);
    exit(0);
}

编译

cc mouse_test.c -lX11 -lXfixes -lXi -o mouse_test

我希望获得鼠标上按钮的数量(7 个),但我总是得到:

Mouse name: Logitech Mechanical keyboard Logitech Mechanical keyboard Keyboard
Number of buttons: 4
Number of keys: 2
Mouse name: ROCCAT ROCCAT Kone Pro Keyboard
Number of buttons: 4
Number of keys: 2
Mouse name: ROCCAT ROCCAT Kone Pro
Number of buttons: 4
Number of keys: 2
Mouse name: ROCCAT ROCCAT Kone Pro
Number of buttons: 4
Number of keys: 2

我想,这可能与linux驱动程序有关,但我不确定

c linux xlib xorg
1个回答
0
投票

我知道您可能期待一个实际的答案,但在我们讨论实证方面之前,我们需要讨论一些“先验”方面,一些哲学和概念问题。 我们将您的鼠标作为物理现实的一部分,这是一回事。软件并不是现实本身,而是代表现实的模型。而作为一个模型,总有局限性、不完美等等。

因此,适当的问题是:您想知道实际物理设备的按钮数量,还是 Xorg 识别的按钮数量?如果你想获取实际物理设备的按钮数量,你需要抓取并数一下。

Xorg 库将为您提供有关这些库所见内容的信息。与某些专有操作系统不同,Xorg 以及 Unix(类似)系统上的大多数东西通常依赖于更通用的驱动程序。因此,一些 Xorg 驱动程序将进行调整,以支持大量设备,使用大量操作系统驱动程序——因为它也可以在多个操作系统上运行。 (PS:我不是 Xorg 或 Xorg 驱动程序方面的专家,所以如果有人可以在这里提供更准确的详细信息,欢迎这样做并稍后删除此注释)

是的,我们的堆栈这里还有另一层,即操作系统,并且 Xorg 驱动程序可能很大程度上依赖于操作系统驱动程序(在您的情况下,是 Linux 内核驱动程序,因为我假设您运行的是 Linux)。因此,这些驱动程序可能会实现您设备的所有功能,也可能不会,并且它们可能会也可能不会向 Xorg 提供有关您实际设备的准确信息。

因此,正如您所看到的,我们的堆栈非常复杂,可能会帮助您获得不准确的信息。

此外,我们还有 X11 协议,这是 80 年代中期的遗留协议,以及 Xorg 对其的实现,以及我们正在运行的库和扩展以及限制因素,以帮助您获取设备上的准确信息。我们需要考虑到我们正在处理一个非常古老的堆栈,太复杂并且是在考虑非常古老的桌面的情况下开发的,它已经过调整、设计和重新设计,以使现代桌面的现代硬件适应旧的想法。

背景知识已经足够了,让我们来看看解决方案。

就像我说的,Xorg 是一个混乱的框架。我们有

XInput

API,而且它很旧,我们有一些更准确和最新的东西,那就是

XInput2
。您的代码使用
XInput
(1),因此这可能是一个限制因素。事实上,我自己的带有很多按钮的鼠标的列出方式与您的完全相同(我的触摸板也是如此)。我对你的原始代码做了一个改编版本,因为我试图在 XWayland 上运行(我不再本地使用 X),但最终我为另一个用户配置了 Xorg 以在 X 上本地测试它。
您的代码还有与我最后解释的问题无关的其他问题,但这里是我使用的:

#include <stdio.h> #include <X11/Xlib.h> #include <X11/extensions/XInput.h> #include <X11/extensions/XI.h> int main (int argc, char **argv, char **envp) { XDeviceInfo mouse_info; XDeviceInfoPtr ptr_mouse_info; XDevice *mouse = NULL; XID mouse_id; XButtonInfoPtr ptr_mouse_buttons; XKeyInfoPtr ptr_mouse_keys; XValuatorInfoPtr ptr_mouse_axes; char * mouse_name = NULL; int num_devices, num_props, i; Display *display = XOpenDisplay(NULL); if (display == NULL) { perror("XOpenDisplay error"); exit(-1); } ptr_mouse_info = XListInputDevices(display, &num_devices); for (i = 0; i < num_devices; i++) { printf("[%d] %s\n", i, ptr_mouse_info[i].name); if (XInternAtom(display, XI_MOUSE, 1) == ptr_mouse_info[i].type) { mouse_id=ptr_mouse_info[i].id; mouse_name=ptr_mouse_info[i].name; mouse = XOpenDevice(display, mouse_id); ptr_mouse_buttons = (XButtonInfoPtr)&ptr_mouse_info[i].inputclassinfo[ButtonClass]; ptr_mouse_keys = (XKeyInfoPtr) &ptr_mouse_info[i].inputclassinfo[KeyClass]; printf("Mouse name: %s\n", mouse_name); printf("Number of buttons: %d\n", ptr_mouse_buttons->num_buttons); printf("Number of keys: %d\n", ptr_mouse_keys->num_keys); } } XFreeDeviceList(ptr_mouse_info); exit(0); }

我的输出,剔除非小鼠条目:

[7] SYNA7DB5:01 06CB:7DB7 Mouse Mouse name: SYNA7DB5:01 06CB:7DB7 Mouse Number of buttons: 4 Number of keys: 2 [12] INSTANT USB GAMING MOUSE Mouse name: INSTANT USB GAMING MOUSE Number of buttons: 4 Number of keys: 2

如您所见,我们的两只鼠标都具有相同数量的按钮和按键,这要么是一个很大的巧合,要么是 
XInput

(1) 不再提供准确的信息。为了测试这是否是代码的问题,我运行了

xinput list --long
,获得了以下信息:
INSTANT USB GAMING MOUSE  Keyboard          id=16   [slave  pointer  (2)]
    Reporting 7 classes:
        Class originated from: 16. Type: XIButtonClass
        Buttons supported: 7
        Button labels: "Button Left" "Button Middle" "Button Right" "Button Wheel Up" "Button Wheel Down" "Button Horiz Wheel Left" "Button Horiz Wheel Right"
SYNA7DB5:01 06CB:7DB7 Touchpad              id=19   [slave  pointer  (2)]
    Reporting 7 classes:
        Class originated from: 19. Type: XIButtonClass
        Buttons supported: 7
        Button labels: "Button Left" "Button Middle" "Button Right" "Button Wheel Up" "Button Wheel Down" "Button Horiz Wheel Left" "Button Horiz Wheel Right"

因此,如果 
xinput list

能够正确检索信息,我对此进行了研究并发现这是一个

XInput
1 问题。所以我尝试使用
XInput2
,代码如下:
#include <X11/Xlib.h>
#include <X11/extensions/XInput2.h>
#include <errno.h>
#include <stdio.h>

int main() {
    int num_buttons;
    int num_keys;
    int ret = 0;

    Display *display = XOpenDisplay(NULL);
    if (display == NULL) {
        fprintf(stderr, "Error opening display");
        goto main_err;
    }

    int opcode, event, error;
    if (!XQueryExtension(display, "XInputExtension", &opcode, &event, &error)) {
        fprintf(stderr, "X Input extension not available.\n");
        goto main_err;
    }

    int num_devices;

    XIDeviceInfo *devices = XIQueryDevice(display, XIAllDevices, &num_devices);
    if (devices == NULL) {
        fprintf(stderr, "XIQueryDevice failed.\n");
        goto main_err;
    }
    for (int i = 0; i < num_devices; i++) {
        int use = devices[i].use;
        int num_classes = devices[i].num_classes;
        if (use == XIMasterPointer || use == XISlavePointer) {
            printf("Device %d:\n", devices[i].deviceid);
            printf("  Name: %s\n", devices[i].name);

            num_buttons = 0;
            num_keys = 0;
            for (int j = 0; j < num_classes; j++) {
                XIAnyClassInfo *class = devices[i].classes[j];
                XIButtonClassInfo *btn;
                XIKeyClassInfo *key;

                if (class->type == XIButtonClass) {
                    btn = (XIButtonClassInfo*) class;
                    num_buttons = btn->num_buttons;
                } else if (class->type == XIKeyClass) {
                    key = (XIKeyClassInfo*) class;
                    num_keys = key->num_keycodes;
                }
            }

            printf("  Buttons: %d\n", num_buttons);
            printf("     Keys: %d\n", num_keys);
            printf("\n");
        }
    }

    XIFreeDeviceInfo(devices);
    XCloseDisplay(display);

    goto main_return;

main_err:
    ret = errno;
    perror("Failure: ");
main_return:
    return ret;
}

通过这段代码,我得到了更准确的(我认为)结果:

Device 15: Name: INSTANT USB GAMING MOUSE Buttons: 9 Keys: 0 Device 19: Name: SYNA7DB5:01 06CB:7DB7 Touchpad Buttons: 7 Keys: 0

因此,我认为我认为您的问题的答案是:如果您确实需要来自 X11 实现的此信息,请使用 XInput2。虽然,如果情况并非如此,我建议使用您操作系统中的某些内容,但这在很大程度上取决于您的要求和建模用户。

不相关的评论

在 Wayland 上,我遇到了分段错误,因为您使用了大量未初始化的指针。永远不要在 C 中这样做,总是初始化你的指针,否则它们将把内存垃圾作为值,并且内存垃圾值指针指向未定义的位置。

© www.soinside.com 2019 - 2024. All rights reserved.