C语言 计数鼠标按钮X11 Linux

ctehm74n  于 2024-01-06  发布在  Linux
关注(0)|答案(1)|浏览(289)

这是我的第一个问题,但我真的迷路了,我需要你的帮助.我写了一个程序在C,打印出鼠标按钮的数量.我决定使用XI. h为此事.该程序的行为奇怪.
这里展示的代码是一个更大程序的代码,这就是为什么包含了这么多库的原因。只是不要看它。
使用的源:XListInputDevicesXInternAtom
程序代码(mouse.c)

  1. #include <X11/Xlib.h>
  2. #include <X11/Xutil.h>
  3. #include <X11/extensions/Xfixes.h>
  4. #include <X11/extensions/XInput.h>
  5. #include <X11/extensions/XI.h>
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <sys/socket.h> /* socket() connect() bind() listen() accept() socketpair() */
  9. #include <sys/types.h>
  10. #include <unistd.h>
  11. #include <string.h> /* strcpy() */
  12. #include <stdio.h> /* perror() */
  13. #include <errno.h> /* error numbers */
  14. #include <stdlib.h>
  15. int main ( void )
  16. {
  17. XDeviceInfo mouse_info;
  18. XDeviceInfoPtr ptr_mouse_info;
  19. XDevice *mouse;
  20. XID mouse_id;
  21. XButtonInfoPtr ptr_mouse_buttons;
  22. XKeyInfoPtr ptr_mouse_keys;
  23. XValuatorInfoPtr ptr_mouse_axes;
  24. char * mouse_name;
  25. int num_devices, num_props, i;
  26. Display *display = XOpenDisplay(NULL);
  27. if (display == NULL)
  28. {
  29. perror("XOpenDisplay error");
  30. exit(-1);
  31. }
  32. ptr_mouse_info = XListInputDevices(display, &num_devices);
  33. for (i = 0; i < num_devices; i++)
  34. {
  35. if (XInternAtom(display, XI_MOUSE, 1) == ptr_mouse_info[i].type)
  36. {
  37. mouse_id=ptr_mouse_info[i].id;
  38. mouse_name=ptr_mouse_info[i].name;
  39. mouse = XOpenDevice(display, mouse_id);
  40. ptr_mouse_buttons = (XButtonInfoPtr)&ptr_mouse_info[i].inputclassinfo[ButtonClass];
  41. ptr_mouse_keys = (XKeyInfoPtr) &ptr_mouse_info[i].inputclassinfo[KeyClass];
  42. printf("Mouse name: %s\n", mouse_name);
  43. printf("Number of buttons: %d\n", ptr_mouse_buttons->num_buttons);
  44. printf("Number of keys: %d\n", ptr_mouse_keys->num_keys);
  45. }
  46. }
  47. printf("Mouse name: %s\n", mouse_name);
  48. printf("Number of buttons: %d\n", ptr_mouse_buttons->num_buttons);
  49. printf("Number of keys: %d\n", ptr_mouse_keys->num_keys);
  50. XFreeDeviceList(ptr_mouse_info);
  51. exit(0);
  52. }

字符串
编译

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


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

  1. Mouse name: Logitech Mechanical keyboard Logitech Mechanical keyboard Keyboard
  2. Number of buttons: 4
  3. Number of keys: 2
  4. Mouse name: ROCCAT ROCCAT Kone Pro Keyboard
  5. Number of buttons: 4
  6. Number of keys: 2
  7. Mouse name: ROCCAT ROCCAT Kone Pro
  8. Number of buttons: 4
  9. Number of keys: 2
  10. Mouse name: ROCCAT ROCCAT Kone Pro
  11. Number of buttons: 4
  12. Number of keys: 2


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

xxls0lw8

xxls0lw81#

我知道你可能期待一个实际的答案,但在我们谈论经验方面之前,我们需要讨论一些先验方面,一些哲学和概念问题。
我们把你的鼠标作为物理现实的一部分,这是一件事。软件不是现实本身,而是一个代表现实的模型。作为一个模型,总是有局限性,不完美等等。
所以,适当的问题是:你想知道你的实际物理设备的按钮的数量,或者Xorg识别的按钮的数量?如果你想获得实际物理设备的按钮的数量,你需要抓住它并计数它。
Xorg库将为您提供有关这些库所看到的信息。与某些专有操作系统不同,Xorg以及Unix(&类)系统上的大多数东西通常依赖于更通用的驱动程序。因此,一些Xorg驱动程序将被调整以支持大量设备,使用大量操作系统驱动程序-因为它也可以在多个操作系统上工作。(PS:我不是Xorg或Xorg驱动程序的Maven,所以如果有人可以在这里提供更准确的细节,欢迎这样做,并删除此说明后)
是的,我们的堆栈在这里还有另一层,操作系统,Xorg驱动程序可能在很大程度上依赖于操作系统驱动程序(在您的情况下,Linux内核驱动程序,因为我假设您运行的是Linux)。因此,这些驱动程序可能实现您设备的所有功能,也可能不实现,它们可能会也可能不会为Xorg提供有关您实际设备的准确信息。
所以,正如你所看到的,我们的堆栈中有一个整体的复杂性,可能会帮助你获得不准确的信息。
此外,我们还有X11协议,这是80年代中期的遗留协议,Xorg对它的实现,我们正在运行的库和扩展以及限制因素,以帮助您获得有关设备的准确信息。我们需要考虑到,我们正在处理一个非常旧的堆栈,太复杂了,开发时考虑到非常旧的桌面,已经进行了调整,设计和重新设计,使现代台式机的现代硬件符合旧的想法。
但足够的背景,让我们去解决方案。
就像我说的,Xorg是一个混乱的框架。我们有XInput API,它很旧,我们有一个更准确和最新的东西,那就是XInput2。你的代码使用XInput(1),所以这可能是一个限制因素。事实上,我自己的鼠标有很多按钮,列出的方式和你的完全一样。(我的触摸板也是)。我做了一个你的原始代码的改编版本,因为我试图在XWayland上运行(我不再使用X本机),但最后我配置了Xorg,让另一个用户在X上测试它。
你的代码有其他问题无关的问题,我会解释在最后,但在这里我使用:

  1. #include <stdio.h>
  2. #include <X11/Xlib.h>
  3. #include <X11/extensions/XInput.h>
  4. #include <X11/extensions/XI.h>
  5. int main (int argc, char **argv, char **envp)
  6. {
  7. XDeviceInfo mouse_info;
  8. XDeviceInfoPtr ptr_mouse_info;
  9. XDevice *mouse = NULL;
  10. XID mouse_id;
  11. XButtonInfoPtr ptr_mouse_buttons;
  12. XKeyInfoPtr ptr_mouse_keys;
  13. XValuatorInfoPtr ptr_mouse_axes;
  14. char * mouse_name = NULL;
  15. int num_devices, num_props, i;
  16. Display *display = XOpenDisplay(NULL);
  17. if (display == NULL)
  18. {
  19. perror("XOpenDisplay error");
  20. exit(-1);
  21. }
  22. ptr_mouse_info = XListInputDevices(display, &num_devices);
  23. for (i = 0; i < num_devices; i++)
  24. {
  25. printf("[%d] %s\n", i, ptr_mouse_info[i].name);
  26. if (XInternAtom(display, XI_MOUSE, 1) == ptr_mouse_info[i].type)
  27. {
  28. mouse_id=ptr_mouse_info[i].id;
  29. mouse_name=ptr_mouse_info[i].name;
  30. mouse = XOpenDevice(display, mouse_id);
  31. ptr_mouse_buttons = (XButtonInfoPtr)&ptr_mouse_info[i].inputclassinfo[ButtonClass];
  32. ptr_mouse_keys = (XKeyInfoPtr) &ptr_mouse_info[i].inputclassinfo[KeyClass];
  33. printf("Mouse name: %s\n", mouse_name);
  34. printf("Number of buttons: %d\n", ptr_mouse_buttons->num_buttons);
  35. printf("Number of keys: %d\n", ptr_mouse_keys->num_keys);
  36. }
  37. }
  38. XFreeDeviceList(ptr_mouse_info);
  39. exit(0);
  40. }

字符串
我的输出,剥离非鼠标条目:

  1. [7] SYNA7DB5:01 06CB:7DB7 Mouse
  2. Mouse name: SYNA7DB5:01 06CB:7DB7 Mouse
  3. Number of buttons: 4
  4. Number of keys: 2
  5. [12] INSTANT USB GAMING MOUSE
  6. Mouse name: INSTANT USB GAMING MOUSE
  7. Number of buttons: 4
  8. Number of keys: 2


正如你所看到的,这可能是一个很大的巧合,我们的两个鼠标都有相同数量的按钮和键,或者XInput(1)不再提供准确的信息。为了测试这是否是代码的问题,我运行了xinput list --long,获得了以下内容:

  1. INSTANT USB GAMING MOUSE Keyboard id=16 [slave pointer (2)]
  2. Reporting 7 classes:
  3. Class originated from: 16. Type: XIButtonClass
  4. Buttons supported: 7
  5. Button labels: "Button Left" "Button Middle" "Button Right" "Button Wheel Up" "Button Wheel Down" "Button Horiz Wheel Left" "Button Horiz Wheel Right"
  6. SYNA7DB5:01 06CB:7DB7 Touchpad id=19 [slave pointer (2)]
  7. Reporting 7 classes:
  8. Class originated from: 19. Type: XIButtonClass
  9. Buttons supported: 7
  10. 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尝试,代码如下:

  1. #include <X11/Xlib.h>
  2. #include <X11/extensions/XInput2.h>
  3. #include <errno.h>
  4. #include <stdio.h>
  5. int main() {
  6. int num_buttons;
  7. int num_keys;
  8. int ret = 0;
  9. Display *display = XOpenDisplay(NULL);
  10. if (display == NULL) {
  11. fprintf(stderr, "Error opening display");
  12. goto main_err;
  13. }
  14. int opcode, event, error;
  15. if (!XQueryExtension(display, "XInputExtension", &opcode, &event, &error)) {
  16. fprintf(stderr, "X Input extension not available.\n");
  17. goto main_err;
  18. }
  19. int num_devices;
  20. XIDeviceInfo *devices = XIQueryDevice(display, XIAllDevices, &num_devices);
  21. if (devices == NULL) {
  22. fprintf(stderr, "XIQueryDevice failed.\n");
  23. goto main_err;
  24. }
  25. for (int i = 0; i < num_devices; i++) {
  26. int use = devices[i].use;
  27. int num_classes = devices[i].num_classes;
  28. if (use == XIMasterPointer || use == XISlavePointer) {
  29. printf("Device %d:\n", devices[i].deviceid);
  30. printf(" Name: %s\n", devices[i].name);
  31. num_buttons = 0;
  32. num_keys = 0;
  33. for (int j = 0; j < num_classes; j++) {
  34. XIAnyClassInfo *class = devices[i].classes[j];
  35. XIButtonClassInfo *btn;
  36. XIKeyClassInfo *key;
  37. if (class->type == XIButtonClass) {
  38. btn = (XIButtonClassInfo*) class;
  39. num_buttons = btn->num_buttons;
  40. } else if (class->type == XIKeyClass) {
  41. key = (XIKeyClassInfo*) class;
  42. num_keys = key->num_keycodes;
  43. }
  44. }
  45. printf(" Buttons: %d\n", num_buttons);
  46. printf(" Keys: %d\n", num_keys);
  47. printf("\n");
  48. }
  49. }
  50. XIFreeDeviceInfo(devices);
  51. XCloseDisplay(display);
  52. goto main_return;
  53. main_err:
  54. ret = errno;
  55. perror("Failure: ");
  56. main_return:
  57. return ret;
  58. }


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

  1. Device 15:
  2. Name: INSTANT USB GAMING MOUSE
  3. Buttons: 9
  4. Keys: 0
  5. Device 19:
  6. Name: SYNA7DB5:01 06CB:7DB7 Touchpad
  7. Buttons: 7
  8. Keys: 0


所以,我认为我假设你的问题的答案是:如果你真的需要这些信息来自你的X11实现,使用XInput 2。虽然,我建议使用你的操作系统中的一些东西,如果不是这样的话,这在很大程度上取决于你的需求和建模用户是什么。
无关评论
在Wayland上,我得到了一个Segmentation Fault,因为你使用了很多未初始化的指针。永远不要在C中这样做,总是初始化你的指针,否则它们将以内存垃圾为值,而内存垃圾值指针指向未定义的位置。

展开查看全部

相关问题