fixed spurious mouse motions when entering/leaving primary
screen on X11.
This commit is contained in:
parent
d813329c0c
commit
217313e013
|
@ -160,44 +160,37 @@ CXWindowsPrimaryScreen::run()
|
||||||
case MotionNotify:
|
case MotionNotify:
|
||||||
{
|
{
|
||||||
log((CLOG_DEBUG2 "event: MotionNotify %d,%d", xevent.xmotion.x_root, xevent.xmotion.y_root));
|
log((CLOG_DEBUG2 "event: MotionNotify %d,%d", xevent.xmotion.x_root, xevent.xmotion.y_root));
|
||||||
SInt32 x = xevent.xmotion.x_root;
|
|
||||||
SInt32 y = xevent.xmotion.y_root;
|
// compute motion delta (relative to the last known
|
||||||
if (!m_active) {
|
// mouse position)
|
||||||
m_server->onMouseMovePrimary(x, y);
|
SInt32 x = xevent.xmotion.x_root - m_x;
|
||||||
|
SInt32 y = xevent.xmotion.y_root - m_y;
|
||||||
|
|
||||||
|
// save position to compute delta of next motion
|
||||||
|
m_x = xevent.xmotion.x_root;
|
||||||
|
m_y = xevent.xmotion.y_root;
|
||||||
|
|
||||||
|
if (xevent.xmotion.send_event) {
|
||||||
|
// we warped the mouse. discard events until we
|
||||||
|
// find the matching sent event. see
|
||||||
|
// warpCursorNoLockNoFlush() for where the events
|
||||||
|
// are sent. we discard the matching sent event
|
||||||
|
// and can be sure we've skipped the warp event.
|
||||||
|
CDisplayLock display(this);
|
||||||
|
do {
|
||||||
|
XMaskEvent(display, PointerMotionMask, &xevent);
|
||||||
|
} while (!xevent.xmotion.send_event);
|
||||||
|
}
|
||||||
|
else if (!m_active) {
|
||||||
|
// motion on primary screen
|
||||||
|
m_server->onMouseMovePrimary(m_x, m_y);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// compute motion delta. this is relative to the
|
// motion on secondary screen. warp mouse back to
|
||||||
// last known mouse position.
|
// center.
|
||||||
x -= m_x;
|
//
|
||||||
y -= m_y;
|
// my lombard (powerbook g3) running linux and
|
||||||
|
// using the adbmouse driver has two problems:
|
||||||
// save position to compute delta of next motion
|
|
||||||
m_x = xevent.xmotion.x_root;
|
|
||||||
m_y = xevent.xmotion.y_root;
|
|
||||||
|
|
||||||
// if event was sent then ignore it and discard
|
|
||||||
// the event from the mouse warp. this is how we
|
|
||||||
// warp the mouse back to the center of the screen
|
|
||||||
// without that causing a corresponding motion on
|
|
||||||
// the secondary screen.
|
|
||||||
if (xevent.xmotion.send_event) {
|
|
||||||
// ignore event
|
|
||||||
x = 0;
|
|
||||||
y = 0;
|
|
||||||
|
|
||||||
// discard events until we find the matching
|
|
||||||
// sent event. see below for where the events
|
|
||||||
// are sent. we discard the matching sent
|
|
||||||
// event and can be sure we've skipped the
|
|
||||||
// warp event.
|
|
||||||
CDisplayLock display(this);
|
|
||||||
do {
|
|
||||||
XMaskEvent(display, PointerMotionMask, &xevent);
|
|
||||||
} while (!xevent.xmotion.send_event);
|
|
||||||
}
|
|
||||||
|
|
||||||
// warp mouse back to center. my lombard (powerbook
|
|
||||||
// g3) using the adbmouse driver has two problems:
|
|
||||||
// first, the driver only sends motions of +/-2
|
// first, the driver only sends motions of +/-2
|
||||||
// pixels and, second, it seems to discard some
|
// pixels and, second, it seems to discard some
|
||||||
// physical input after a warp. the former isn't a
|
// physical input after a warp. the former isn't a
|
||||||
|
@ -211,28 +204,15 @@ CXWindowsPrimaryScreen::run()
|
||||||
xevent.xmotion.y_root - m_yCenter < -s_size ||
|
xevent.xmotion.y_root - m_yCenter < -s_size ||
|
||||||
xevent.xmotion.y_root - m_yCenter > s_size) {
|
xevent.xmotion.y_root - m_yCenter > s_size) {
|
||||||
CDisplayLock display(this);
|
CDisplayLock display(this);
|
||||||
// send an event that we can recognize before
|
warpCursorNoLockNoFlush(display, m_xCenter, m_yCenter);
|
||||||
// the mouse warp.
|
|
||||||
XEvent eventBefore = xevent;
|
|
||||||
xevent.xmotion.window = m_window;
|
|
||||||
xevent.xmotion.time = CurrentTime;
|
|
||||||
xevent.xmotion.x = m_xCenter;
|
|
||||||
xevent.xmotion.y = m_yCenter;
|
|
||||||
xevent.xmotion.x_root = m_xCenter;
|
|
||||||
xevent.xmotion.y_root = m_yCenter;
|
|
||||||
XEvent eventAfter = eventBefore;
|
|
||||||
XSendEvent(display, m_window, False, 0, &xevent);
|
|
||||||
|
|
||||||
// warp mouse back to center
|
|
||||||
XWarpPointer(display, None, getRoot(),
|
|
||||||
0, 0, 0, 0, m_xCenter, m_yCenter);
|
|
||||||
|
|
||||||
// send an event that we can recognize after
|
|
||||||
// the mouse warp.
|
|
||||||
XSendEvent(display, m_window, False, 0, &xevent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// send event if mouse moved
|
// send event if mouse moved. do this after warping
|
||||||
|
// back to center in case the motion takes us onto
|
||||||
|
// the primary screen. if we sent the event first
|
||||||
|
// in that case then the warp would happen after
|
||||||
|
// warping to the primary screen's enter position,
|
||||||
|
// effectively overriding it.
|
||||||
if (x != 0 || y != 0) {
|
if (x != 0 || y != 0) {
|
||||||
m_server->onMouseMoveSecondary(x, y);
|
m_server->onMouseMoveSecondary(x, y);
|
||||||
}
|
}
|
||||||
|
@ -331,28 +311,18 @@ CXWindowsPrimaryScreen::enter(SInt32 x, SInt32 y, bool forScreenSaver)
|
||||||
|
|
||||||
CDisplayLock display(this);
|
CDisplayLock display(this);
|
||||||
|
|
||||||
// warp to requested location
|
|
||||||
if (!forScreenSaver) {
|
|
||||||
XWarpPointer(display, None, m_window, 0, 0, 0, 0, x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
// unmap the grab window. this also ungrabs the mouse and keyboard.
|
// unmap the grab window. this also ungrabs the mouse and keyboard.
|
||||||
XUnmapWindow(display, m_window);
|
XUnmapWindow(display, m_window);
|
||||||
|
|
||||||
// redirect input to root window
|
// warp to requested location
|
||||||
if (forScreenSaver) {
|
if (!forScreenSaver) {
|
||||||
XSetInputFocus(display, PointerRoot, PointerRoot, CurrentTime);
|
warpCursorNoLock(display, x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove all input events for grab window
|
// redirect input to root window. do not warp the mouse because
|
||||||
XEvent event;
|
// that will deactivate the screen saver.
|
||||||
while (XCheckWindowEvent(display, m_window,
|
else {
|
||||||
PointerMotionMask |
|
XSetInputFocus(display, PointerRoot, PointerRoot, CurrentTime);
|
||||||
ButtonPressMask | ButtonReleaseMask |
|
|
||||||
KeyPressMask | KeyReleaseMask |
|
|
||||||
KeymapStateMask,
|
|
||||||
&event)) {
|
|
||||||
// do nothing
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// not active anymore
|
// not active anymore
|
||||||
|
@ -414,7 +384,7 @@ CXWindowsPrimaryScreen::leave()
|
||||||
} while (result != GrabSuccess);
|
} while (result != GrabSuccess);
|
||||||
log((CLOG_DEBUG1 "grabbed pointer and keyboard"));
|
log((CLOG_DEBUG1 "grabbed pointer and keyboard"));
|
||||||
|
|
||||||
// move the mouse to the center of grab window
|
// warp mouse to center
|
||||||
warpCursorNoLock(display, m_xCenter, m_yCenter);
|
warpCursorNoLock(display, m_xCenter, m_yCenter);
|
||||||
|
|
||||||
// local client now active
|
// local client now active
|
||||||
|
@ -439,18 +409,16 @@ CXWindowsPrimaryScreen::warpCursor(SInt32 x, SInt32 y)
|
||||||
void
|
void
|
||||||
CXWindowsPrimaryScreen::warpCursorNoLock(Display* display, SInt32 x, SInt32 y)
|
CXWindowsPrimaryScreen::warpCursorNoLock(Display* display, SInt32 x, SInt32 y)
|
||||||
{
|
{
|
||||||
assert(display != NULL);
|
// warp mouse
|
||||||
assert(m_window != None);
|
warpCursorNoLockNoFlush(display, x, y);
|
||||||
|
|
||||||
// warp the mouse
|
// remove all input events before and including warp
|
||||||
XWarpPointer(display, None, getRoot(), 0, 0, 0, 0, x, y);
|
XEvent event;
|
||||||
XSync(display, False);
|
while (XCheckMaskEvent(display, PointerMotionMask |
|
||||||
log((CLOG_DEBUG2 "warped to %d,%d", x, y));
|
ButtonPressMask | ButtonReleaseMask |
|
||||||
|
KeyPressMask | KeyReleaseMask |
|
||||||
// discard mouse events since we just added one we don't want
|
KeymapStateMask,
|
||||||
XEvent xevent;
|
&event)) {
|
||||||
while (XCheckWindowEvent(display, m_window,
|
|
||||||
PointerMotionMask, &xevent)) {
|
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -459,6 +427,41 @@ CXWindowsPrimaryScreen::warpCursorNoLock(Display* display, SInt32 x, SInt32 y)
|
||||||
m_y = y;
|
m_y = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CXWindowsPrimaryScreen::warpCursorNoLockNoFlush(
|
||||||
|
Display* display, SInt32 x, SInt32 y)
|
||||||
|
{
|
||||||
|
assert(display != NULL);
|
||||||
|
assert(m_window != None);
|
||||||
|
|
||||||
|
// send an event that we can recognize before the mouse warp
|
||||||
|
XEvent eventBefore;
|
||||||
|
eventBefore.type = MotionNotify;
|
||||||
|
eventBefore.xmotion.display = display;
|
||||||
|
eventBefore.xmotion.window = m_window;
|
||||||
|
eventBefore.xmotion.root = getRoot();
|
||||||
|
eventBefore.xmotion.subwindow = m_window;
|
||||||
|
eventBefore.xmotion.time = CurrentTime;
|
||||||
|
eventBefore.xmotion.x = x;
|
||||||
|
eventBefore.xmotion.y = y;
|
||||||
|
eventBefore.xmotion.x_root = x;
|
||||||
|
eventBefore.xmotion.y_root = y;
|
||||||
|
eventBefore.xmotion.state = 0;
|
||||||
|
eventBefore.xmotion.is_hint = False;
|
||||||
|
eventBefore.xmotion.same_screen = True;
|
||||||
|
XEvent eventAfter = eventBefore;
|
||||||
|
XSendEvent(display, m_window, False, 0, &eventBefore);
|
||||||
|
|
||||||
|
// warp mouse
|
||||||
|
XWarpPointer(display, None, getRoot(), 0, 0, 0, 0, x, y);
|
||||||
|
|
||||||
|
// send an event that we can recognize after the mouse warp
|
||||||
|
XSendEvent(display, m_window, False, 0, &eventAfter);
|
||||||
|
XSync(display, False);
|
||||||
|
|
||||||
|
log((CLOG_DEBUG2 "warped to %d,%d", x, y));
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CXWindowsPrimaryScreen::setClipboard(ClipboardID id,
|
CXWindowsPrimaryScreen::setClipboard(ClipboardID id,
|
||||||
const IClipboard* clipboard)
|
const IClipboard* clipboard)
|
||||||
|
|
|
@ -42,6 +42,8 @@ private:
|
||||||
void doSelectEvents(Display*, Window) const;
|
void doSelectEvents(Display*, Window) const;
|
||||||
void warpCursorNoLock(Display*,
|
void warpCursorNoLock(Display*,
|
||||||
SInt32 xAbsolute, SInt32 yAbsolute);
|
SInt32 xAbsolute, SInt32 yAbsolute);
|
||||||
|
void warpCursorNoLockNoFlush(Display*,
|
||||||
|
SInt32 xAbsolute, SInt32 yAbsolute);
|
||||||
|
|
||||||
KeyModifierMask mapModifier(unsigned int state) const;
|
KeyModifierMask mapModifier(unsigned int state) const;
|
||||||
KeyID mapKey(XKeyEvent*) const;
|
KeyID mapKey(XKeyEvent*) const;
|
||||||
|
|
Loading…
Reference in New Issue