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.
Related
I am working on a MFC app which is a MDI. One of the child frame uses OpenGL(mixed with fixed function and modern version) called 3d view and another child frame uses GDI called plan view. Both of the views use the same doc.
The 3d view has a function to detect if the mouse cursor is over rendered 3d model by reading pixels and check its depth value.
The function is used for WM_MOUSEMOVE and WM_LBUTTONDOWN events. Most time it works pretty well. But it failed when I move my cursor from the plan view(currently active) to the 3d view and left mouse click. The depth values read from the pixels(called from onLButtonDown) are always all zeros though it is over a model. There is no OpenGL error reported. It only fails on the first mouse click when the 3d view is not activated. Afterwards, everything works well again.
The issue doesn't happen on all machines. And it happens to me but not to another guy with the same hardware machine with me. Is that possible hardware related or a code bug?
Things tried:
I tried to increase the pixel block size much bigger but depths are still all zero.
If I click on the title bar of the 3d view to activate it first, then works.
I tried to set the 3d view active and foreground in the onLButtonDown method before reading pixels. But still failed.(btw, the 3d view should be active already before the OnLButtonDown handler via other message handler fired by the left button down).
I tried to invalidate rect before reading pixels, failed too.
The code is as below:
BOOL CMy3DView::IsOverModel(int x0, int y0, int &xM, int &yM, GLfloat &zWin, int width0 , int height0 )
{
int width = max(1,width0);
int height= max(1,height0);
CRect RectView;
GetClientRect(&RectView);
GLint realy = RectView.Height() - 1 - (GLint)y0 ; /* OpenGL y coordinate position */
std::vector<GLfloat> z(width*height);
//Read the window z co-ordinates the z value of the points in a rectangle of width*height )
xM = max(0, x0-(width-1)/2);
yM = max(0, realy-(height-1)/2);
glReadPixels(xM, yM, (GLsizei)width, (GLsizei)height, GL_DEPTH_COMPONENT, GL_FLOAT, &z[0]); OutputGlError(_T("glReadPixels")) ;
/* check pixels along concentric, nested boxes around the central point */
for (int k=0; k<=(min(height,width)-1)/2; ++k){
for (int i=-k;i<=k;++i){
xM = x0+i;
for (int j=-k;j<=k;++j){
if (abs(i)==k || abs(j)==k) {
yM = realy+j;
zWin=z[(i+(width-1)/2)+width*(j+(height-1)/2)];
if (zWin<1.0-FLT_EPSILON) break;
}
}
if (zWin<1.0-FLT_EPSILON) break;
}
if (zWin<1.0-FLT_EPSILON) break;
}
yM = RectView.Height() - 1 - yM;
if (zWin>1.0-FLT_EPSILON || zWin<FLT_EPSILON) {// z is the depth, between 0 and 1, i.e. between Near and Far plans.
xM=x0; yM=y0;
return FALSE;
}
return TRUE;
}
Just found a solution for that: I called render(GetDC) before any processing in OnLButtonDown. somehow it fixed the issue though I don't think it's necessary.
InvalideRect wont fix the issue since it will update the view for the next WM_PAINT.
Weird, since it works for some machines without the fix. Still curious about the reason.
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.
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);
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
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;