使用Xlib获取鼠标点击坐标

3
我希望了解如何在屏幕上的任何位置使用Xlib获取鼠标单击的x和y坐标。我发现了这篇文章,它可以获取当前指针位置。 如何在X中获取当前鼠标(指针)位置坐标 但我不知道如何修改它以便在鼠标单击时获取x y坐标。 我尝试编写了此代码,但它没有任何作用。
#include <stdio.h>
#include <stdlib.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>

int main (){
int x=-1,y=-1;
XEvent event;
int button;
Display *display = XOpenDisplay(NULL);
if (display == NULL) {
    fprintf(stderr, "Cannot connect to X server!\n");
    exit (EXIT_FAILURE);
}
Window root= XDefaultRootWindow(display);
XSelectInput(display, root, ButtonReleaseMask) ;
while(1){
XNextEvent(display,&event);
switch(event.type){
    case ButtonRelease:
        switch(event.xbutton.button){
            case Button1:
                x=event.xbutton.x;
                y=event.xbutton.y;
                button=Button1;
                break;

            case Button3:
                x=event.xbutton.x;
                y=event.xbutton.y;
                button=Button3;
                break;
            default:
                break;

        }
        break;
    default:
        break;
}
if(x>=0 && y>=0)break;
}
if(button==Button1)printf("leftclick at %d %d \n",x,y);
else printf("rightclick at %d %d \n",x,y);
XCloseDisplay(display);
return 0;
}

事件可能被发送到其他窗口,这就是它不起作用的原因。另一个问题是当我在XSelectInput函数中添加ButtonPressMask时,会出现以下错误:
X Error of failed request:  BadAccess (attempt to access private resource denied)
Major opcode of failed request:  2 (X_ChangeWindowAttributes)
Serial number of failed request:  7
Current serial number in output stream:  7

如果在C语言中有更简单的方法来实现这个,我很乐意听取。
3个回答

6

我知道这已经过去几年了,所以这对其他人来说是信息性的。首先,使用另一个库并不符合我的定义更加简单。我正在使用xlib和C语言编写需要此功能的项目,并且我想看看我能不能使代码更简单。

实际上,在现有程序中使用xlib只需要四行代码就可以完成这项任务,其余的都取决于你如何处理它,例如printf / sprintf、grab_pixel_color(Display *display, XColor *color)等。

/** gcc position.c -o position -lX11 **/
#include <X11/Xlib.h>
#include <stdio.h>

int main (int argc, char **argv) {
    Window root_window; //<--one
    int root_x, root_y; //<--two
    unsigned int mask; //<--three

    Display *display = XOpenDisplay(NULL);

    /*
    Bool XQueryPointer(display, w, root_return, child_return, root_x_return, root_y_return,
                         win_x_return, win_y_return, mask_return)
          Display *display;
          Window w;
          Window *root_return, *child_return;
          int *root_x_return, *root_y_return;
          int *win_x_return, *win_y_return;
          unsigned int *mask_return;
    */

    XQueryPointer(display, DefaultRootWindow(display), &root_window, &root_window, &root_x, &root_y, &root_x, &root_y, &mask); //<--four

    printf("Mouse coordinates (X: %d, Y: %d)\n", root_x, root_y);

    XCloseDisplay(display);
    return 0;
}

我希望这对其他人有所帮助。

1
杰出的答案(无论OP是否要求事件)。请不要从这个答案中删除任何内容。 - duanev

3

您可能需要获取指针。

我不知道您是只想获取按钮按下还是释放情况。我已将其更改为按下,但您可以使用以下代码同时获取两种情况:

XSelectInput(display, root, ButtonPressMask|ButtonReleaseMask) ;

并将ButtonRelease案例添加回来。
#include <stdio.h>
#include <stdlib.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>

int main (){
    int x=-1,y=-1;
    XEvent event;
    int button;
    Display *display = XOpenDisplay(NULL);
    if (display == NULL) {
    fprintf(stderr, "Cannot connect to X server!\n");
    exit (EXIT_FAILURE);
    }
    Window root= XDefaultRootWindow(display);
    XGrabPointer(display, root, False, ButtonPressMask, GrabModeAsync,
         GrabModeAsync, None, None, CurrentTime);

    XSelectInput(display, root, ButtonPressMask) ;
    while(1){
    XNextEvent(display,&event);
    switch(event.type){
    case ButtonPress:
        switch(event.xbutton.button){
        case Button1:
        x=event.xbutton.x;
        y=event.xbutton.y;
        button=Button1;
        break;

        case Button3:
        x=event.xbutton.x;
        y=event.xbutton.y;
        button=Button3;
        break;
        default:
        break;

        }
        break;
    default:
        break;
    }
    if(x>=0 && y>=0)break;
    }
    if(button==Button1)printf("leftclick at %d %d \n",x,y);
    else printf("rightclick at %d %d \n",x,y);
    XCloseDisplay(display);
    return 0;
}

谢谢,代码对我来说很好用,但我不得不改成ButtonRelease,否则我会得到与上述描述相同的错误。你知道为什么吗? - rex123
两个事件对我都有效。你使用的是哪个窗口管理器?我正在使用KDE窗口管理器。 - parkydr
我做了一些研究,你的问题似乎是由于其他进程已经从根窗口捕获了按钮按下事件,我可以通过运行两个实例来重现这个问题(第二个会出现此错误)。 - parkydr

1
如果在C语言中有更简单的方法,我很乐意听取建议。
太棒了!那么使用libxdo库,一些人已经为你准备好了。
int x, y, scrn;

xdo_t *hndl = xdo_new(NULL);
xdo_mouselocation(hndl, &x, &y, &scrn);
xdo_free(hndl);

printf("Mouse coordinates: x = %4d, y = %4d\n", x, y);

谢谢。这个库比xlib本身容易使用得多,非常适合我的项目。但是我还没有看到任何返回鼠标点击时坐标的函数,因为你的示例只在调用时返回坐标。 - rex123

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接