-
Notifications
You must be signed in to change notification settings - Fork 946
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for notifying clients about pointer movements #1198
Conversation
The failures were caused by Docker authentication limits. I swear I did not break the build ^^;; |
This change adds the following: a) A new button on the UI to enter full pointer lock mode, which invokes the Pointer Lock API[1] on the canvas, which hides the cursor and makes mouse events provide relative motion from the previous event (through `movementX` and `movementY`). These can be added to the previously-known mouse position to convert it back to an absolute position. b) Adds support for the VMware Cursor Position pseudo-encoding[2], which servers can use when they make cursor position changes themselves. This is done by some APIs like SDL, when they detect that the client does not support relative mouse movement[3] and then "warp"[4] the cursor to the center of the window, to calculate the relative mouse motion themselves. c) When the canvas is in pointer lock mode and the cursor is not being locally displayed, it updates the cursor position with the information that the server sends, since the actual position of the cursor does not matter locally anymore, since it's not visible. d) Adds some tests for the above. You can try this out end-to-end with TigerVNC with TigerVNC/tigervnc#1198 applied! Fixes: novnc#1493 under some circumstances (at least all SDL games would now work). 1: https://developer.mozilla.org/en-US/docs/Web/API/Pointer_Lock_API 2: https://github.com/rfbproto/rfbproto/blob/master/rfbproto.rst#vmware-cursor-position-pseudo-encoding 3: https://hg.libsdl.org/SDL/file/28e3b60e2131/src/events/SDL_mouse.c#l804 4: https://tronche.com/gui/x/xlib/input/XWarpPointer.html
This change adds the following: a) A new button on the UI to enter full pointer lock mode, which invokes the Pointer Lock API[1] on the canvas, which hides the cursor and makes mouse events provide relative motion from the previous event (through `movementX` and `movementY`). These can be added to the previously-known mouse position to convert it back to an absolute position. b) Adds support for the VMware Cursor Position pseudo-encoding[2], which servers can use when they make cursor position changes themselves. This is done by some APIs like SDL, when they detect that the client does not support relative mouse movement[3] and then "warp"[4] the cursor to the center of the window, to calculate the relative mouse motion themselves. c) When the canvas is in pointer lock mode and the cursor is not being locally displayed, it updates the cursor position with the information that the server sends, since the actual position of the cursor does not matter locally anymore, since it's not visible. d) Adds some tests for the above. You can try this out end-to-end with TigerVNC with TigerVNC/tigervnc#1198 applied! Fixes: novnc#1493 under some circumstances (at least all SDL games would now work). 1: https://developer.mozilla.org/en-US/docs/Web/API/Pointer_Lock_API 2: https://github.com/rfbproto/rfbproto/blob/master/rfbproto.rst#vmware-cursor-position-pseudo-encoding 3: https://hg.libsdl.org/SDL/file/28e3b60e2131/src/events/SDL_mouse.c#l804 4: https://tronche.com/gui/x/xlib/input/XWarpPointer.html
This change adds the following: a) A new button on the UI to enter full pointer lock mode, which invokes the Pointer Lock API[1] on the canvas, which hides the cursor and makes mouse events provide relative motion from the previous event (through `movementX` and `movementY`). These can be added to the previously-known mouse position to convert it back to an absolute position. b) Adds support for the VMware Cursor Position pseudo-encoding[2], which servers can use when they make cursor position changes themselves. This is done by some APIs like SDL, when they detect that the client does not support relative mouse movement[3] and then "warp"[4] the cursor to the center of the window, to calculate the relative mouse motion themselves. c) When the canvas is in pointer lock mode and the cursor is not being locally displayed, it updates the cursor position with the information that the server sends, since the actual position of the cursor does not matter locally anymore, since it's not visible. d) Adds some tests for the above. You can try this out end-to-end with TigerVNC with TigerVNC/tigervnc#1198 applied! Fixes: novnc#1493 under some circumstances (at least all SDL games would now work). 1: https://developer.mozilla.org/en-US/docs/Web/API/Pointer_Lock_API 2: https://github.com/rfbproto/rfbproto/blob/master/rfbproto.rst#vmware-cursor-position-pseudo-encoding 3: https://hg.libsdl.org/SDL/file/28e3b60e2131/src/events/SDL_mouse.c#l804 4: https://tronche.com/gui/x/xlib/input/XWarpPointer.html
Nice. I'll try to have a look and comment. Have you also looked at adding support to our viewer? We prefer if features are fully implemented in both client and server so we can test properly without external projects. |
not originally, but let me see how hard would it be. |
Turns out most of the functionality was already there! Used this little snippet of code[1] because fltk does not support relative mouse events and the cursor eventually hit a wall at the edges of the screen and broke everything unless we also mirrored the cursor-warping that was done remotely. 1: https://www.mail-archive.com/[email protected]/msg00023.html |
6d1de4f
to
0029a49
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks really nice. Good work!
Please also merge the two fix commits in too the others so we just have the two original commits. You can rebase and force push to fix up this.
How is this best tested? And what other servers and clients implement this?
vncviewer/DesktopWindow.cxx
Outdated
Window rootwindow = DefaultRootWindow(fl_display); | ||
XWarpPointer(fl_display, rootwindow, rootwindow, 0, 0, 0, 0, | ||
pos.x, pos.y); | ||
#endif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The coordinates here look wrong. The VNC screen might not be at coordinates 0,0, so everything here needs to be adjusted by an offset.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
haha, this is my first change of a client application, so i basically stumbled upon a solution that worked for me in this one case (translation: please suggest what offset should be added).
i kinda guess that the viewport->x/y()
is what we want, but have no way of confirming since i don't know any situations other than the one i can test locally.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see two test scenarios:
- Viewport doesn't match window. Just disable "Resize remote session..." in the options and make sure the session is larger or smaller than your client window
- Client is on different monitors. You need two monitors for this, and disable "Enable full-screen mode over all monitors"
I would suspect you need both viewport->x/y()
and window()->x/y()
to properly get screen coordinates.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
both cases seemed to work with a combination of x_root() + viewport->x()
. thanks!
491daa9
to
ee0e0ef
Compare
Done
So far only noVNC and this are the only open source server/clients that will implement this (after a quick Sourcegraph search). To test, run any SDL game that captures the cursor. In a pinch, running https://gist.github.com/lhchavez/50f4c31fc3faf811c3a572148479ef1b (requires Python3 and pygame) should do the trick. |
ee0e0ef
to
536b679
Compare
vncviewer/DesktopWindow.cxx
Outdated
if (!mouseGrabbed) { | ||
// Do nothing if we do not have the mouse captured. | ||
return; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We probably shouldn't do this if we aren't focused as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wouldn't that make it hard to exit the client? in any case, moved to #1212.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How so? The warping should generally be in the way in such cases, not helping?
vncviewer/DesktopWindow.cxx
Outdated
Window rootwindow = DefaultRootWindow(fl_display); | ||
XWarpPointer(fl_display, rootwindow, rootwindow, 0, 0, 0, 0, | ||
pos.x + x_root() + viewport->x(), | ||
pos.y + y_root() + viewport->y()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have you tried this with Wayland? It doesn't seem to work for me here. :/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no, and i don't have a wayland environment :( is there a way to detect Wayland and not do this there? (in any case, moved to #1212).
vncviewer/DesktopWindow.cxx
Outdated
@@ -51,6 +51,8 @@ | |||
|
|||
#ifdef __APPLE__ | |||
#include "cocoa.h" | |||
#include <CoreGraphics/CGGeometry.h> | |||
#include <CoreGraphics/CGRemoteOperation.h> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The compiler can't find these here. I'm using an older SDK and gcc instead of clang. Hower #include <Carbon/Carbon.h>
works for me. Does that work for you?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i don't have a macOS device ^^;; i was just fiddling until i got it working on CI. what's preferable in these cases? to drop support for macOS altogether? (in any case, moved to #1212).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It works for me with those changes, so go with that. :)
Doesn't seem to work on Windows either. macOS kind-a works, but there seems to be something generally wrong there unrelated to your changes. |
536b679
to
b151bbd
Compare
splitting this change into server-side (the one i really care about) and client-side, since it seems that the client-side will take more time. |
b151bbd
to
75d36b7
Compare
We don't want you disappearing on us once the server is merged though, so I prefer the one PR. :) |
The fix for macOS seems to be this at least: diff --git a/vncviewer/DesktopWindow.cxx b/vncviewer/DesktopWindow.cxx
index bb51019e..385a9e88 100644
--- a/vncviewer/DesktopWindow.cxx
+++ b/vncviewer/DesktopWindow.cxx
@@ -188,6 +187,14 @@ DesktopWindow::DesktopWindow(int w, int h, const char *name,
// Show hint about menu key
Fl::add_timeout(0.5, menuOverlay, this);
+
+ // By default we get a slight delay when we warp the pointer, something
+ // we don't want or we'll get jerky movement
+#ifdef __APPLE__
+ CGEventSourceRef event = CGEventSourceCreate(kCGEventSourceStateCombinedSessionState);
+ CGEventSourceSetLocalEventsSuppressionInterval(event, 0);
+ CFRelease(event);
+#endif
}
|
don't worry about that, i promise right here and now to finish the whole thing. disappearing once the server is merged through will contribute to building a bad relationship with you, and I already have a lot of PRs open in repositories you own, so it's in my best interest to see through all of them (within reason: i'm probably not going to go buy a Mac just to test these changes ^^;; ). but on the other hand, throw a man a bone! this is the part of the change that i have a vested interest in (and ultimately what motivates me to do the other parts). i see the vncviewer part as "building goodwill" (other less charitable folks call it the "open source contributor tax"). |
i have no idea why Travis is complaining about |
Unrelated and fixed on |
This change adds support for the VMware Mouse Position pseudo-encoding[1], which is used to notify VNC clients when X11 clients call `XWarpPointer()`[2]. This function is called by SDL (and other similar libraries) when they detect that the server does not support native relative motion, like some RFB clients. With this, RFB clients can choose to adjust the local cursor position under certain circumstances to match what the server has set. For instance, if pointer lock has been enabled on the client's machine and the cursor is not being drawn locally, the local position of the cursor is irrelevant, so the RFB client can use what the server sends as the canonical absolute position of the cursor. This ultimately enables the possibility of games (especially FPS games) to behave how users expect (if the clients implement the corresponding change). Part of: TigerVNC#619 1: https://github.com/rfbproto/rfbproto/blob/master/rfbproto.rst#vmware-cursor-position-pseudo-encoding 2: https://tronche.com/gui/x/xlib/input/XWarpPointer.html 3: https://hg.libsdl.org/SDL/file/28e3b60e2131/src/events/SDL_mouse.c#l804
75d36b7
to
cb8629a
Compare
yay, thanks! i was stumped for a bit there as to how the other PR wasn't getting in the same situation. |
is this change also good to merge? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup. The only notes where about the client side of things.
For reference, the vncviewer side of this: #1212 |
This change adds the following: a) A new button on the UI to enter full pointer lock mode, which invokes the Pointer Lock API[1] on the canvas, which hides the cursor and makes mouse events provide relative motion from the previous event (through `movementX` and `movementY`). These can be added to the previously-known mouse position to convert it back to an absolute position. b) Adds support for the VMware Cursor Position pseudo-encoding[2], which servers can use when they make cursor position changes themselves. This is done by some APIs like SDL, when they detect that the client does not support relative mouse movement[3] and then "warp"[4] the cursor to the center of the window, to calculate the relative mouse motion themselves. c) When the canvas is in pointer lock mode and the cursor is not being locally displayed, it updates the cursor position with the information that the server sends, since the actual position of the cursor does not matter locally anymore, since it's not visible. d) Adds some tests for the above. You can try this out end-to-end with TigerVNC with TigerVNC/tigervnc#1198 applied! Fixes: novnc#1493 under some circumstances (at least all SDL games would now work). 1: https://developer.mozilla.org/en-US/docs/Web/API/Pointer_Lock_API 2: https://github.com/rfbproto/rfbproto/blob/master/rfbproto.rst#vmware-cursor-position-pseudo-encoding 3: https://hg.libsdl.org/SDL/file/28e3b60e2131/src/events/SDL_mouse.c#l804 4: https://tronche.com/gui/x/xlib/input/XWarpPointer.html
This change adds support for the VMware Mouse Position
pseudo-encoding[1], which is used to notify VNC clients when X11 clients
call
XWarpPointer()
[2]. This function is called by SDL[3] (and othersimilar libraries) when they detect that the server does not support
native relative motion, like some RFB clients.
With this, RFB clients can choose to adjust the local cursor position
under certain circumstances to match what the server has set. For
instance, if pointer lock has been enabled on the client's machine and
the cursor is not being drawn locally, the local position of the cursor
is irrelevant, so the RFB client can use what the server sends as the
canonical absolute position of the cursor. This ultimately enables the
possibility of games (especially FPS games) to behave how users expect
(if the clients implement the corresponding change).
You can try this out end-to-end with noVNC with
novnc/noVNC#1520 applied!
Part of: #619
1: https://github.com/rfbproto/rfbproto/blob/master/rfbproto.rst#vmware-cursor-position-pseudo-encoding
2: https://tronche.com/gui/x/xlib/input/XWarpPointer.html
3: https://hg.libsdl.org/SDL/file/28e3b60e2131/src/events/SDL_mouse.c#l804