2

I have an application which uses Xlib library for simulate a mouse on the screen.

I used XQueryPointer and XWarpPointer functions with which I can simulate a mouse movement and also a click. My problem is that I can't "drag" an element (it's an interface with some blocks which you can move within a Qt application written in C++ and launched on Ubuntu).

I use many parts of this extract:

Sending X11 click event doesn't work with some windows

Can this function help me?

::XGrabPointer(mDisplay, window, True,
           ButtonPressMask |
             ButtonReleaseMask |
             PointerMotionMask |
             FocusChangeMask |
             EnterWindowMask |
              LeaveWindowMask,
           GrabModeAsync,
           GrabModeAsync,
           RootWindow(mDisplay, DefaultScreen(mDisplay)),
           None,
           CurrentTime);

Do you have any idea?

Thank you in advance.

Community
  • 1
  • 1
Damien
  • 63
  • 1
  • 1
  • 6

2 Answers2

2

If you're okay with spawning a child process, you can easily use xdotool for this, as in:

xdotool mousedown 1
sleep 0.5
xdotool mousemove_relative --sync 200 200
sleep 0.5
xdotool mouseup 1

http://www.semicomplete.com/projects/xdotool/

http://tuxradar.com/content/xdotool-script-your-mouse

The source code to xdotool would serve as a good starting point if you want to do this yourself in C with the XTest library.

Blake Miller
  • 805
  • 11
  • 16
1

You can achieve this by sending the XMotionEvent to the window. the way X11 know that it is a drag event is by checking the state. So, if the state is OR with the Button1Mask then it means that the Motion is done when the Button1 was pressed.

I am pasting the pseudo code here. You might want to populate the relevant fields of the XMotionEvent as per your use-case.

Display *OpenedDisplay = XOpenDisplay(NULL);

int ret = 0,screen = 0;
XMotionEvent xbpe;

Window dummy;
unsigned int mask,dummyUInt;
int dummyInt;

int screencount = ScreenCount(xbpe.display);
for (int i = 0; i < screencount; i++) {
    Screen *screenPointer = ScreenOfDisplay(xbpe.display, i);
    ret = XQueryPointer(xbpe.display, RootWindowOfScreen(screenPointer), &dummy, &dummy,
                        &dummyInt, &dummyInt, &dummyInt, &dummyInt, &mask);
    if (ret == True) {
      screen = i;
      break;
    }
}

xbpe.type = MotionNotify;
xbpe.display = OpenedDisplay;
xbpe.window = wid;
xbpe.root = RootWindow(xbpe.display, screen);
xbpe.subwindow = None;
xbpe.time = CurrentTime;
xbpe.x = src_x;
xbpe.y = src_y;

xbpe.state = mask;
xbpe.is_hint = NotifyNormal;
xbpe.same_screen = True; /* Should we detect if window is on the same screen as cursor? */

XWindowAttributes attr;
ret = XGetWindowAttributes(xbpe.display, wid, &attr);
if(ret == 0){
    qDebug() << wid <<"XGetWindowAttributes unsuccessfull returning early";
    return;
}
/**************************** This is key here *******************/
if(isDrag){
    xbpe.state |= Button1Mask;
}

ret = XSendEvent(xbpe.display, wid, False, PointerMotionMask|ButtonMotionMask|MotionNotify, (XEvent *)&xbpe);
XFlush(OpenedDisplay);
XCloseDisplay(OpenedDisplay);

I would recommend navigating the source code of xdotool. It doesn't specifically covers your issue but gives you enough information on populating the fields of X*Event.

Mohit
  • 1,859
  • 1
  • 16
  • 25