How to determine which way the mouse is being dragged (Win32, C++) - c++

I am currently working on a project which requires me to know when the mouse is being dragged to the left, or to the right.
What I would like to do with this information, is drag an object in 3d space (with OpenGL/Win32), left, or right, depending on which way the mouse was dragged.
The problem is, I have no idea how to determine which way the mouse is being dragged.
I tried finding the previous x coordinate, and subtracting it from the current x coordinate, but I do not know how to determine the previous x coordinate!
Can someone please help me?
(P.S. I already know that the current x mouse location is found with LOWORD(lParam), but what I do not know is how to determine the previous x mouse location. Thanks for your time.)

You could do it yourself by storing the current mouse position as the 'last' mouse position, and then after two mouse position updates, subtract.
onMouseMove(mouseX, mouseY):
if previousX and previousY are set:
deltaX = previousX - mouseX
deltaY = previousY - mouseY
actOnDrag(deltaX, deltaY)
previousX = mouseX
previousY = mouseY
You could set previousX and previousY to some crazy sentinel value (e.g. -1) to determine whether they have ever been set.

You could use the DragDetect function.
BOOL DragDetect(HWND hwnd, POINT pt);
https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-dragdetect

Related

How to keep mouse coordinates within window height/width limits

Suppose I have a 600 by 600 window created through glfwCreateWindow().
I have a few models rendered in the scene and to move around them in the 3D space I use a camera class which moves around with my cursor as well as AWSD/spacebar keys.
To make the movement "seamless" I use glfwSetInputMode(this->window, GLFW_CURSOR, GLFW_CURSOR_DISABLED).
Now then the problem is that I am also trying to implent a mouse picker of sorts (casting ray from cursor position to the scene).
So I implemented the mouse picker from a video I found on yt, but it doesnt work properly. The reason being is that my mouse X and Y coordinates get bigger than width and height if for example I rotate on spot (and I can increase it this way indefinitely).
I understand that this is happening because I have no cursor to be bound within resolution limits due to glfwSetInputMode(this->window, GLFW_CURSOR, GLFW_CURSOR_DISABLED). I am asking how I should correct this so that I can keep the seamlessness as well as be able to limit the cursor coordinates within width and height (otherwise the mouse picker function wont work because normalized mouse coordinates go over [1,1] which completely breaks it and so on).
I will be grateful for any answers.
EDIT:
#httpdigest's answer put into very elementary code:
//store offsetX and offsetY values (and dont forget to give them 0 as initial value)
overshootX = mouseX - offsetX;
overshootY = mouseY - offsetY;
if (overshootX > width) {
offsetX = offsetX + overshootX - width;
}
if (overshootX < 0) {
offsetX = offsetX + overshootX;
}
if (overshootY > height) {
offsetY = offsetY + overshootY - height;
}
if (overshootY < 0) {
offsetY = offsetY + overshootY;
}
float withinWindowCursorPosX = mouseX - offsetX;
float withinWindowCursorPosY = mouseY - offsetY;
One way of doing it is to store an offset (initially (0, 0)) by how much the cursor moved beyond the bounds of the window/viewport (separate for X and Y).
Essentially, everytime when you either read the current cursor position or are being told of an update by an event, you calculate overshoot = cursorPos - offset (separate for X and Y). If overshoot exceeds (width, height) you increment offset by the excess it exceeded (width, height). Likewise, if overshoot is less than (0, 0) you decrement offset by the negative overshoot.
That way, you have a "sliding" window/rectangle which gets slided around as you keep on moving the mouse cursor beyond either edge of the screen.
Now, whenever you want to obtain the corrected cursor position (within your window), you simply use withinWindowCursorPos = cursorPos - offset.
You can then use withinWindowCursorPos for your picking calculations that require a cursor within the window/viewport.

mouse input: MOUSEEVENTF_MOVE moving not according to dx, dy

In the below codes, it is expected my mouse cursor would be set to (100,100) on the screen. However, it turns out the cursor is moved to (2,1).
And when MOUSEEVENTF_ABSOLUTE is not set, I expected the mouse would move 100 pixels to the right and bottom respectively. While the result is it moved from (352, 65) to (670, 383).
INPUT Input[1];
ZeroMemory(Input, sizeof(INPUT) * 1);
Input[0].type = INPUT_MOUSE;
Input[0].mi.dx = 100;
Input[0].mi.dy = 100;
Input[0].mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE;
SendInput(1, Input, sizeof(INPUT));
Posts I have read:
I have realized that there is another post about the similar situation. But I suspect whether memory leak is the answer since I used cout to check the value of Input[0].mi.dx and Input[0].mi.dy and they are exact 100.
From the solution of the top voted post in here, factors are used to modify the xy values. Even so, the result is not accurate to your input. And the answer did not explain why a factor need to be used.
My question:
1) What is the accurate way to move cursor in Windows beside using SetCursorPos()? (there is a reason I don't want to use it)
2) Does anyone knows the reasons behind the unreasonable movement with MOUSEEVENTF_MOVE?
Okay in QT how to find the Mouse Position: I am Current making a program that uses the QMouseMoveEvent Quite heavily.
So step by step, lets create a new project, with a blank MainMenu form. Slap a new Label down so we can see the X Y coords change.
This works for QT Create a new function and call it
void MainWindow::mouseMoveEvent(QMouseEvent *event), make sure to add it in the .h too!
Then using the event varible create a pointer to it. QPoint pos = event->pos();
Then do pos.x(), pos.y(); and put them into your label/output and there we go!
Then use them coords to do as you wish with.
I hope this is the answer your looking for!
If you need more help i can link you to my GitHub repo and you can view some of my work on X Y positions and Lat Lon to X Y;
Also just as a last thing if you are looking to do Lat Lon to X Y its this
X is current mouse X coord;
Y is current mouse Y Coord;
double lat = (y * 180) / ("Height in pixels of scene")-90
double lon = (x * 360) / ("Width in Pixels of scene")-180
Also one last thing to set the positon in QT simply use
QCursor my_cursor;
my_cursor.setPos(X,Y);
Not sure about getting the Dx/Dy but this is a small example that may help you understand more about this. Anyway I hope what I put has helped
Are you taking into account that X/Y Coords start at 0,0 at the top left hand corner?
What Complier are you using?
Its hard to fix a problem when we don't know what libraries we need to use to fix this.
Because if this is in QT its an easy fix. But im not too sure about using it in MFC or another C++ GUI.
More detail would be nice :) - get back to me ill have another look into your issue
A couple things come to mind:
int CURSOR_X;
int CURSOR_Y;
int mousex;
int mousey;
CURSOR_X = 100;
CURSOR_Y = 100;
SetCursorPos(CURSOR_X, CURSOR_Y);
mouse_event(MOUSEEVENTF_MOVE | MOUSEEVENTF_MOVE, 100, mousex, mousey, 100);

Capture Mouse Position

This is a Win32 program, and I Write a CaptureMousePosition function to capture the mouse's position.
and I call the function in WM_MOUSEMOVE message.
Then I run the program.when my mouse moves on the red point, it is (126,112).There is no problem here.
But when my mouse moves on the blue point,it becomes (960,940).How can it happen,I don't understand, why the red point is (126,112),but the blue point is (960,940).the blue point should be ( < 126, < 112).how to fix it.
Everything is just fine. The coordinates of the blue dot are X = 96 and Y = 94. You are seeing X = 960 because you are not erasing the 0 left over from X = 100. You would have noticed that the values are just fine if you had used a debugger to step through the code.
The documentation for WM_MOUSEMOVE clearly states:
Use the following code to obtain the horizontal and vertical position:
xPos = GET_X_LPARAM(lParam);
yPos = GET_Y_LPARAM(lParam);
As noted above, the x-coordinate is in the low-order short of the return value; the y-coordinate is in the high-order short (both represent signed values because they can take negative values on systems with multiple monitors). If the return value is assigned to a variable, you can use the MAKEPOINTS macro to obtain a POINTS structure from the return value. You can also use the GET_X_LPARAM or GET_Y_LPARAM macro to extract the x- or y-coordinate.
Important Do not use the LOWORD or HIWORD macros to extract the x- and y- coordinates of the cursor position because these macros return incorrect results on systems with multiple monitors. Systems with multiple monitors can have negative x- and y- coordinates, and LOWORD and HIWORD treat the coordinates as unsigned quantities.
Change this:
short nX;
nX = (short)LOWORD(lParam);
short nY;
nY = (short)HIWORD(lParam);
To this:
short nX;
nX = GET_X_LPARAM(lParam);
short nY;
nY = GET_Y_LPARAM(lParam);
Or this:
POINTS pt;
pt = MAKEPOINTS(lParam);
short nX;
nX = pt.x;
short nY;
nY = pt.y;
Update: something else to note from the documentation:
Posted to a window when the cursor moves. If the mouse is not captured, the message is posted to the window that contains the cursor. Otherwise, the message is posted to the window that has captured the mouse.
That means if the mouse has been captured via SetCapture(), the reported coordinates will be relative to the window that is doing the capturing, not the window that the mouse is actually moving over.
Without showing your code, is hard to answer, but I guess, that problem is in Screen vs. Client coordinates.

Using glut to prevent the mouse from leaving the window

I'm using glut for a game right now and I'm trying to keep the mouse inside the window. This isn't a first person shooter so locking it in the center is no good. I already know about glutWarpPointer(int, int); and I've trying things that work (kinda).
I've tried having the mouse warp back to the nearest edge of the window when it leaves, this works, but for a split second you see the mouse outside of the window and teleport back in. I don't want that, I want it to seem like the mouse just hits the edge of the window and stops going any further in that direction, while keeping movement in any other available direction. Like you would expect it to work.
This is not exactly an answer to your question, but it is an answer to your problem!
Almost every game has its own cursors. They would hide the mouse, and draw the cursor manually where the mouse should be positioned.
If you get your own cursor image and do as I said, you can simply draw the curser at the edge of the screen, even though the mouse position reads out of boundaries. Then you can warp the mouse back in.
Tried to search and figure this out and couldn't find an answer, so I implemented it myself. Here is what worked for my first person camera case:
callback from glutPassiveMotion
CODE SAMPLE
void Game::passiveMouseMotion(int x, int y)
{
//of my code for doing the cam, yours is may be different, this is based on the example from https://learnopengl.com/Getting-started/Camera
if (firstMouse) {
lastX = x;
lastY = y;
firstMouse = false;
}
float xoffset = x - lastX;
float yoffset = lastY - y; // reversed since y-coordinates go from bottom to top
lastX = x;
lastY = y;
camera->ProcessMouseMovement(xoffset, yoffset);
glutPostRedisplay();
//this is the main thing that keeps it from leaving the screen
if ( x < 100 || x > win_w - 100 ) { //you can use values other than 100 for the screen edges if you like, kind of seems to depend on your mouse sensitivity for what ends up working best
lastX = win_w/2; //centers the last known position, this way there isn't an odd jump with your cam as it resets
lastY = win_h/2;
glutWarpPointer(win_w/2, win_h/2); //centers the cursor
} else if (y < 100 || y > win_h - 100) {
lastX = win_w/2;
lastY = win_h/2;
glutWarpPointer(win_w/2, win_h/2);
}
}
Hope this helps!

Relative mouse position of SDL_Surface

In my application I need to return the relative mouse position from an SDL_Surface, the problem is the mouse position that gets returned is relative to the SDL window and not the SDL_Surface. I guess my question is what is the easiest / most effective way of doing this. Any questions just ask. Thanks.
EDIT: Sorry I should have explained better, I have SDL_Surface* Surf_Display; on Surf_display there is an Image say its 1000 x 1000, So in order to see the image on a 600 x 600 window I have a camera that I can move around ( really its the surface that moves not the camera ) for instance to look right of the image I move the surface -1 left if that makes sense. So my problem is when I click my mouse on a part of the surface(image) my mouse returns the position that the mouse compared to where the cursor is in the window, what i'm wanting is so that it returns the position of the cursor compared to where it is on the surface(image)
I hope that better explains the situation. Thanks again
Just add(or subtract, depending on how you look at it) the offset to the mouse coordinates. So you're drawing the surface something like this:
SDL_Rect dest_rect = { -camera.x, -camera.y };
SDL_BlitSurface(image_surface, NULL, screen_surface, &dest_rect);
I don't know if you're using event based mouse handling, or if you're using SDL_GetMouseState, but either way, you would simply add camera.x and camera.y to the mouse position, for example:
int x, y;
SDL_GetMouseState(&x, &y);
x += camera.x;
y += camera.y;