I'm wondering how I can get the original HCURSOR of whatever happens to be set as the mouse arrow pointer. I've already tried using GetCursor(), but it just gets whatever cursor is currently displayed on screen. Here's a section of my code:
COLORREF *hide;
HBITMAP bmp;
hide = (COLORREF*) malloc(sizeof(hide) * 1);
bmp = CreateBitmap(1, 1, 1, 32, (void *) hide);
ICONINFO Ico;
Ico.fIcon = false;
Ico.hbmColor = bmp;
Ico.hbmMask = bmp;
HCURSOR c = CreateIconIndirect(&Ico);
HCURSOR orgc = GetCursor();
SetSystemCursor(c, 32512);
Sleep(10);
SetSystemCursor(orgc, 32512);
DeleteObject(bmp);
I intend for it to hide the cursor, then wait for ten milliseconds, then bring the original cursor back without having to use the resize trick. Any suggestions?
I intend for it to hide the cursor, then wait for ten milliseconds, then bring the original cursor back without having to use the resize trick. Any suggestions?
ShowCursor(FALSE);
Sleep(10);
ShowCursor(TRUE);
I don't know what you mean by "the resize trick."
If you meant something else by "the original cursor," then perhaps a deeper understanding of how cursors are selected would be helpful.
Each window is responsible for setting the cursor as the mouse moves across it. Whenever the mouse moves within a window then, assuming the mouse is not captured, that window will receive a WM_SETCURSOR message. The name of the message can be a little confusing. Think of it as a notification to the window that this is its chance to change the cursor.
The window procedure can choose its cursor shape by calling SetCursor and then return TRUE to indicate that no other handlers be given the opportunity to process the message. There's nothing that denotes a particular cursor as an arrow cursor, wait cursor, crosshairs, etc. It's just the currently selected shape.
This (normally) happens for each WM_MOUSEMOVE. So it's very common for a window procedure to set the same cursor over and over again, so the system is designed to optimize for that. But allowing the window to decide what to should after each mouse move gives the window the opportunity to show different characters depending on where exactly within the window the mouse pointer is.
Whenever a SetCursor calls specifies a different cursor than the current one, it returns the HCURSOR of the previously selected one.
Many window procedures do not explicitly handle WM_SETCURSOR messages and instead passes them on to the default window procedure (DefWndProc). The default window procedure first relays the message to the parent window if there is one. This can happen recursively so that the root ancestor is the first window to get a choice to change the cursor.
If the parent handles the message and returns TRUE, then processing stops. So your application's main window can decide that the cursor should look like a chicken even if some of its child windows would want to select something else.
If no ancestor windows handle the message, then DefWndProc will check to see if the window has an HCURSOR set in its window class (WNDCLASS or WNDCLASSEX). If the windows class does specify a cursor, then DefWndProc will set that as the cursor. If the class cursor is NULL, DefWndProc does not set any cursor.
The system cursors are a set of defaults for different modes. If an application wants a wait cursor, it can call LoadCursor(NULL, IDC_WAIT) and get the HCURSOR of whatever cursor the user has selected as the system's default wait cursor. You shouldn't set the system cursors unless you're providing an interface for the user to set the system defaults.
I am trying to make an application which will graphically repeat the mouse pointer, so I can ultimately make a mouse trail program, for Ubuntu 18.04 - and it seems, the way to do it is via X11/Xlib - although, these days I don't even know, as my machine says also wayland:
$ loginctl | while IFS= read line; do echo "$line"; if [[ $line == *"tty"* ]]; then sessnum=$(echo "$line" | awk '{print $1;}'); echo sessnum: $sessnum\; $(loginctl show-session $sessnum -p Type); fi; done
SESSION UID USER SEAT TTY
c1 121 gdm seat0 tty1
sessnum: c1; Type=wayland
2 1000 administrator seat0 tty2
sessnum: 2; Type=x11
2 sessions listed.
Regardless, I managed to put together an unholy assemblage of:
https://keithp.com/blogs/Cursor_tracking/ - which sets up the program for capturing raw mouse events, so the mouse pointer position can be extracted (and a redraw triggered) whenever the mouse pointer position changes
xosd.c (via https://github.com/AndreRenaud/XOSD) - I thought at first that On-Screen Display would have a special method to draw on top - but this sets up a topmost window, child of the root, where all drawing happens; and it also sets up event and timer thread
.... plus a ton of other code snippets (mostly from SO), which sort of does what I want (even if I don't really fully understand all of the layers and compositing that goes on in it). I posted this as a gist: xosd_track_cursor.c since it's 700+ lines (but can post it here if needed).
Here is how the application behaves (also see full-res imgur .mp4 video)
Basically, at start, the "OSD" topmost window is set up, and it's quite smaller than the desktop window - which helps us see the window border decorations around it (ultimately, I'd make this window the same size as the desktop).
At start, the desktop pixels at the location of this window have seemingly been copied as the window background.
Once the mouse pointer enters the OSD window, there is a draw of a circle, which becomes the mask for the OSD window (which again can be seen via the window border decorations) - and this circular window follows the mouse. Then, inside it, I draw a XFillRectangle to draw a lime rectangle, and then XPutImage to draw the pixels captured from the latest mouse pointer (the video doesn't show it, but also the copied cursor changed when the normal one does, say from left_ptr to bottom_side or xterm cursor bitmaps).
So far so good - but these are the problems, and questions:
All of the draws - both the lime rectangle and the mouse pointer copy - remain on the OSD window, and are not cleared upon redraw (which is quite obvious when the mouse pointer leaves the OSD window, so there is no masking). How can I erase these previous draws each time a new state is rendered?
When I click on window to change the focus, it is obvious (especially when the mouse pointer leaves the OSD window, so there is no masking) that the desktop "background" shown in the OSD window, shows the state when the program started. How can I capture the current state of the desktop background (that is, behind the OSD window), so I can use that for clearing the OSD window in the previous step?
(I thought I could hide the OSD window, then capture the desktop at the same location with XGetImage, maybe (?) - then show the window; but show always sends Expose event, which otherwise runs the expose function that does the redraw, and so I get a bunch of recursive calls hogging the application)
The mouse pointer copy is rendered with a black background - how can I make the drawing of mouse pointer copy transparent, where it is black now?
And, a sort of a bonus question (just curious here - obviously I'd rather not have the leftovers to begin with):
I first do XFillRectangle to draw a lime rectangle, then XPutImage to draw the pixels of the mouse pointer copy. I'd expect this to show the mouse cursor copy on top of the green pixels - and it is indeed so, while the OSD window is masked with the circle. But when the OSD window is shown in full, the leftovers make it seem as if the green pixels were drawn on top of the mouse cursor copy pixels. Why is this so?
Well, I think I got somewhere - the result is in the same gist, just different revision: gist: xosd_track_cursor.c (a31e9dff5); and it looks like this:
And so, to answer my questions:
How can I erase these previous draws each time a new state is rendered?
Cannot - not in the way the previous code was set up. It was set up as a override_redirect, meaning it would stay out of the management of any window manager. Furthermore, the default bit depth was 24, meaning that transparency was not supported, meaning that to grab the desktop "behind" (to use as "clear" background), we'd had to hide and then show the window, which used to cause recursion due to reaction to Expose events.
However, I saw in How to make an OpenGL rendering context with transparent background? that using an glXCreateContext might help - and it did. However, it turns out, it was not necessary - as soon as XMatchVisualInfo successfully returned a match for 32-bit depth for the OSD window (alpha transparency supported), then it was possible to define a "fully transparent" color, via XSetForeground, as 0x00000000 (as far as I see, that is 0xAARRGGBB format) - and use that to draw directly on the window with XFillRectangle -> that manages to clear the entire OSD window transparently.
The mouse pointer copy is rendered with a black background - how can I make the drawing of mouse pointer copy transparent, where it is black now?
Turns out, also this started working as soon as the window was created with XCreateWindow using settings from XMatchVisualInfo for 32-bit depth. By that, I mean that the result of XPutImage was such, that the transparent points in the cursor image were now "see-through"/transparent - whereas previously, the result of XPutImage showed black pixels at those locations.
But when the OSD window is shown in full, the leftovers make it seem as if the green pixels were drawn on top of the mouse cursor copy pixels. Why is this so?
Apparently, I didn't remember correctly what order the pixels were drawn in; when that demo capture was taken, indeed the mouse cursor pixels were copied first, and then the green pixels were copied on top. ( which now changes the question - how come the mouse cursor was visible in that capture, at all?! but now that the overall problem is solved, I'm not that curious :) )
Otherwise, few more notes on gist: xosd_track_cursor.c (a31e9dff5): since X11 has a client/server architecture, that means the user program can only queue requests to the server, and thus all of the drawing calls are asynchronous/non-blocking - and so, when we run, say, XFillRectangle and it exits, it does not mean that the drawing of pixels has been finished - just that the request has been sent to the queue, that ends up being sent to the server. Furthermore, in spite of commands like XFlush, XSync - there is never a guarantee that we can wait for a finished drawing operation; and there is no guarantee either that the server will honor any given request.
However, the less you try to do, the bigger the probability the X Server will honor the requests. So this version of the code actually makes a smallish window, 60x60 pixels, then sets it up so it is (centrally aligned) dragged by the motion of the mouse pointer. Then, the (main) mouse pointer is simply copied in this window at the same relative location.
Finally, there is a primitive attempt to do a mouse trail, by rendering two "ghost" copies of the mouse pointer, and have them be displaced by a history of mouse motion delta vector - the effect, as is visible on the gif, is not really amazing, but at least it's there as a "proof of concept", of sorts. Also, the window is setup at start as "click-through" using XShapeCombineRectangles - meaning the OSD window doesn't pick up/handle any mouse events (clicks) directly on it, instead everything is automatically passed to the windows below it, so the interaction remains the same, as if the program was not running at all.
(Note that to get the behavior of gist: xosd_track_cursor.c (a31e9dff5) shown in the gif, you should look up the defines DEBUGPRINT and MOUSE_TRAIL, and have them uncommented when you build)
Title pretty much says it all: I'm wondering whether it's possible to change the mouse cursor icon in response to feedback in a terminal app (e.g., a click event) from the ncurses library or another library?
For example: I am running xterm under X, and a curses application inside that xterm. I may or may not be sshed into another box.
A user clicks on an element of my cursor app -- is it possible to change the mouse cursor icon from a bar to a plus sign in response to the click?
There is some information here but I'd like a more complete resource:
Mouse movement events in NCurses
I don't believe it is. ncurses can read events from the mouse but not actually change mouse cursor settings. The terminal sends mouse movement and clicks to the ncurses program as escape sequences.
Some terminals, such as putty, will change the cursor to an arrow when a region is clickable. Otherwise, a text selection cursor is shown. But I don't think this is controllable through escape sequences.
I cannot not find any way to restore the Saved Window Position without seeing the Window jump from its initial default Position to the Restored Position. The problem is that the first time I get access to the Window its already visible to the user. Am I missing something or is there currently no way to do this?
Try adjusting OOB Settings, Width=1, Height=1
It is not ideal, but tolerable.
The window opens very small, then resizes correctly.
I also found that when restoring the window position, you have to set the Width and Height first, then Top and Left. Otherwise there appears to be a bug which sometimes resets the top or left.
I'm having amazing difficulties with a high-precision pixel-oriented image program in WPF and starting to suspect that the Cursors.Cross cursor hotspot is not at its centre, as you would expect.
I'm debugging using Magnifier at 16x and mouse set to the lowest acceleration. The code is based on DrawTools from CodeProject.
Is this the same cursor as you get in Winforms? If so, I can look at that cursor's hotspot - the Cursor class in System.Windows.Input doesn't have the HotSpot property.
UPDATE
In case anyone is looking for a workaround, in my case I already have a delegate being invoked to filter the points so I can implement snap-to-grid behaviour. It was trivial to offset the point by 1 to compensate. This was a lot easier than creating a custom cursor and has the advantage that I'm still using the stock cursor if its appearance should change.
I have an empirical answer that yes, the hotspot is offset.
I modified the program to be able to trigger graphics modes by pressing keys, so you don't need to move the mouse.
Using the same Magnifier view as the snapshot above, just pressing a key to change the mode toggles the cursor between arrow and cross.
When I switch it draws the cursor so the black lines centre on the top-left point of the normal arrow cursor.
The arrow cursor hotspot is at the pixel it points to (not a black pixel) so yes, the cross cursor hotspot is NOT at the centre of the crosshairs!
sigh