get weird cursor position - c++

Ok so I'm working with vectors today yaya!
well im also working with getcursorpos() and i get weird results.
here is the code:
VOID fRegularShot(HDC hdc, HWND hWnd)
{
Graphics graphics(hdc);
Image shot(L"RegularShots.png");
long index=0;
while(index<=(long)pRegularShots.size())
{
index+=2;
int x=pRegularShots.at(index);
int y1=index+1;
int y=pRegularShots.at(y1);
graphics.DrawImage(&shot, x, y);
}
}
///////////////////////////////////////////////////
event
case WM_LBUTTONDOWN:
iRegularShots=0;
POINT pt;
GetCursorPos(&pt);
pRegularShots.insert(pRegularShots.begin()+1, pt.y);
pRegularShots.insert(pRegularShots.begin()+1, pt.x);
InvalidateRect(hWnd, rect, false);
break;
Well basically function fregularshots() get called and use the vector elements which contains the positions of the cursor than draws the image on the cursor positions.
but it doesn't seem to draw it on the cursor positions.
any ideas?

GetCursorPos returns cursor position in screen coordinates. Use ScreenToClient(hWnd, ...) to convert it to window client coordinates.
GetCursorPos(&pt);
ScreenToClient(hWnd, &pt);
You can work also without GetCursorPos function. When WM_LBUTTONDOWN notification is received, lParam contains window client mouse coordinates: x in low-order word, y in high-order word:
xPos = GET_X_LPARAM(lParam);
yPos = GET_Y_LPARAM(lParam);
Edit:
Let's make this code more simple.
vector<POINT> pRegularShots;
VOID fRegularShot(HDC hdc, HWND hWnd)
{
Graphics graphics(hdc);
Image shot(L"RegularShots.png");
long index=0;
while(index < (long)pRegularShots.size())
{
graphics.DrawImage(&shot, pRegularShots[index].x, pRegularShots[index].y);
++index;
}
}
case WM_LBUTTONDOWN:
POINT pt;
pt.x = GET_X_LPARAM(lParam);
pt.y = GET_Y_LPARAM(lParam);
pRegularShots.push_back(pt);
InvalidateRect(hWnd, rect, false);
break;

Related

Why when I paint, and the mouse is moving in the window, the painting is not done at the same time everywhere? (WinAPI)

After asking this question, I changed my code. It works, but when WM_PAINT paints the window and the cursor is moving in it, the painting is not done at the same time everywhere. Here you have a video to see it better. This is my WM_PAINT:
//TV is a struct with the dimensions of the window.
//BitmapBuffer is the bitmap containing the painting.
static int cont;
cont++;
HDC HDc;
PAINTSTRUCT ps;
HDc = BeginPaint(identifier, &ps);
Gdiplus::Graphics lienzo (HDc);
AlphaBlend(HDc, 0, 0, TV.width+4, TV.height+4, buffer, 0, 0, TV.width+4, TV.height+4, CopyInfo);
EndPaint(identifier, &ps);
Since the problem is when moving the mouse, maybe the WM_NCHITTEST message has something to do with it:
case WM_NCHITTEST:
POINTS point1 = MAKEPOINTS(lParam);
POINT point2;
point2.x = point1.x;
point2.y = point1.y;
ScreenToClient(hwnd, &point2);
if (PtInRegion(region, point2.x, point2.y))
{
if (inWindow == false) //inWindow is true when the cursor is in the window
{
inWindow = true;
TrackMouseEvent(&structure);
Repaint(); //this function repaint the buffer and after call invalidrect
}
return HTCLIENT;
}
else
{
if (inWindow == true)
{
inWindow = false;
Repaint();
}
return HTTRANSPARENT;
}
break;
Does anyone have an idea why this happens?
It's hard to see the problem, because your code doesn't define Repaint. However, you should be using InvalidateRect to tell Windows which area is being updated.
THAT SAID...
Windows is hard to program for updating images with out using a double buffering technique. This is when you draw to a memory (bitmap) then bitblt the bitmap to the screen.
You find this answer useful Reduce flicker with GDI+ and C++

How to read a range of pixels c++

I'm doing a program that reads a range of pixels and if find the red color, do a click with left mouse button, but it is too slow, like if the red dot shows up on the range, it takes 2 seconds or more to click.
This is a representation of the problem:
So if some red dot cross the green line, click with left mouse button. The green line do not exist, I drew it just to make it clearer.
Can someone propose a solution to read this interval in milliseconds?
I think that the problem is to use a for loop to check the pixel colors.
I tried to use the solution proposed in the topic "Get Pixel color fastest way?" but this made the computer very slow and did not work. (I made some adjustments to adapt the solution to my problem). Also, because my problem is much simpler, I think there is a simpler solution than the one in the other topic, which is more complex and did not work for me.
This is my code:
int main()
{
HDC dc = GetDC(NULL);
POINT pt;
int x = 150;
while (1) {
for (int y = 205; y >= 0; y--) {
dc = GetDC(NULL);
COLORREF color = GetPixel(dc, x, y);
// the red color has value = 220
if (color == 220) {
GetCursorPos(&pt);
mouse_event(MOUSEEVENTF_LEFTDOWN, pt.x, pt.y, 0, 0);
mouse_event(MOUSEEVENTF_LEFTUP, pt.x, pt.y, 0, 0);
}
}
}
ReleaseDC(NULL, dc);
}
Should you be getting a new image every time you're checking the pixel color? Off the top of my head maybe GETDC should be before the for loop.
while (1) {
dc = GetDC(NULL);
for (int y = 205; y >= 0; y--) {
COLORREF color = GetPixel(dc, x, y);

Search icon in edit control overlapped by input area

I am trying to make a search edit control in MFC that has an icon displayed in the control window all the time (regardless the state and text of the control). I have written something like this many years ago and worked very well, but the code no longer works on Windows 7 and newer (maybe even Vista, but did not try that). What happens is that the image shown in the control is overlapped with the input area (see the picture below).
The idea behind the code:
have a class derived from CEdit (that handles painting in OnPaint)
the icon is displayed on the right and the edit area is shrunk based on the size of the icon
resizing is done differently for single-line and multiline edits. For single line I call SetMargins and for multiline edits I call SetRect.
this edit resizing is applied in PreSubclassWindow(), OnSize() and OnSetFont()
This is how the edit input size is applied:
void CSymbolEdit::RecalcLayout()
{
int width = GetSystemMetrics( SM_CXSMICON );
if(m_hSymbolIcon)
{
if (GetStyle() & ES_MULTILINE)
{
CRect editRect;
GetRect(&editRect);
editRect.right -= (width + 6);
SetRect(&editRect);
}
else
{
DWORD dwMargins = GetMargins();
SetMargins(LOWORD(dwMargins), width + 6);
}
}
}
The following image shows the problem with the single line edits (the images have been zoomed in for a better view). The yellow background is for highlighting purposes only, in real code I am using the COLOR_WINDOW system color. You can see that when the single line edit has text and has the input the left side image is painted over. This does not happen with the multiline edit where SetRect correctly sets the formatting rectangle.
I have tried using ExcludeClipRect to remove the area of the edit where the image is being displayed.
CRect rc;
GetClientRect(rc);
CPaintDC dc(this);
ExcludeClipRect(dc.m_hDC, rc.right - width - 6, rc.top, rc.right, rc.bottom);
DWORD dwMargins = GetMargins();
SetMargins(LOWORD(dwMargins), width + 6);
This does not seem to have any effect on the result.
For reference, this is the painting method, written years ago and used to work well on Windows XP, but not correct any more.
void CSymbolEdit::OnPaint()
{
CPaintDC dc(this);
CRect rect;
GetClientRect( &rect );
// Clearing the background
dc.FillSolidRect( rect, GetSysColor(COLOR_WINDOW) );
DWORD dwMargins = GetMargins();
if( m_hSymbolIcon )
{
// Drawing the icon
int width = GetSystemMetrics( SM_CXSMICON );
int height = GetSystemMetrics( SM_CYSMICON );
::DrawIconEx(
dc.m_hDC,
rect.right - width - 1,
1,
m_hSymbolIcon,
width,
height,
0,
NULL,
DI_NORMAL);
rect.left += LOWORD(dwMargins) + 1;
rect.right -= (width + 7);
}
else
{
rect.left += (LOWORD(dwMargins) + 1);
rect.right -= (HIWORD(dwMargins) + 1);
}
CString text;
GetWindowText(text);
CFont* oldFont = NULL;
rect.top += 1;
if(text.GetLength() == 0)
{
if(this != GetFocus() && m_strPromptText.GetLength() > 0)
{
oldFont = dc.SelectObject(&m_fontPrompt);
COLORREF color = dc.GetTextColor();
dc.SetTextColor(m_colorPromptText);
dc.DrawText(m_strPromptText, rect, DT_LEFT|DT_SINGLELINE|DT_EDITCONTROL);
dc.SetTextColor(color);
dc.SelectObject(oldFont);
}
}
else
{
if(GetStyle() & ES_MULTILINE)
CEdit::OnPaint();
else
{
oldFont = dc.SelectObject(GetFont());
dc.DrawText(text, rect, DT_SINGLELINE | DT_INTERNAL | DT_EDITCONTROL);
dc.SelectObject(oldFont);
}
}
}
I have looked at other implementations of similar edit controls and they all have the same fault now.
Obviously, the question is how do I exclude the image area from the input area of the control?
I think what's going on is that CPaintDC calls BeginPaint(), which sends a WM_ERASEBKGND to the edit box. I wasn't able to ignore it, so I guess it's being sent to maybe an internal STATIC window? Not sure.
Calling ExcludeClipRect() in your OnPaint() handler won't do anything because EDIT will reset the clipping region to the whole client area in either BeginPaint() or its own WM_PAINT handler.
However, EDIT sends a WM_CTRCOLOREDIT to its parent just before painting itself, but seemingly after setting the clipping region. So you can call ExcludeClipRect() there. Sounds like an implementation detail which may change with future versions of the common controls. Indeed, it seems to have done so already.
I did a quick test without MFC on Windows 7, here's my window procedure:
LRESULT CALLBACK wnd_proc(HWND h, UINT m, WPARAM wp, LPARAM lp)
{
switch (m)
{
case WM_CTLCOLOREDIT:
{
const auto dc = (HDC)wp;
const auto hwnd = (HWND)lp;
RECT r;
GetClientRect(hwnd, &r);
// excluding the margin, but not the border; this assumes
// a one pixel wide border
r.left = r.right - some_margin;
--r.right;
++r.top;
--r.bottom;
ExcludeClipRect(dc, r.left, r.top, r.right, r.bottom);
return (LRESULT)GetStockObject(DC_BRUSH);
}
}
return ::DefWindowProc(h, m, wp, lp);
}
I then subclassed the EDIT window to draw my own icon in WM_PAINT, and then forwarded the message so I didn't have to draw everything else myself.
LRESULT CALLBACK edit_wnd_proc(
HWND h, UINT m, WPARAM wp, LPARAM lp,
UINT_PTR id, DWORD_PTR data)
{
switch (m)
{
case WM_PAINT:
{
const auto dc = GetDC(h);
// draw an icon
ReleaseDC(h, dc);
break;
}
}
return DefSubclassProc(h, m, wp, lp);
}
Note that I couldn't call BeginPaint() and EndPaint() (the equivalent of constructing a CPaintDC) in WM_PAINT because the border wouldn't get drawn. I'm guessing it has something to do with calling BeginPaint() twice (once manually, once by EDIT) and the handling of WM_ERASEBKGND. YMMV, especially with MFC.
Finally, I set the margins right after creating the EDIT:
SendMessage(
e, EM_SETMARGINS,
EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELPARAM(0, margin));
You might also have to update the margins again if the system font changes.
Have a look at this tutorial... from www.catch22.net. It gives a clear picture of how to insert a button into edit control. Though it is an Win32 example, this can be improvised to MFC as the basic structure of MFC is using win32 apis.
http://www.catch22.net/tuts/win32/2001-05-20-insert-buttons-into-an-edit-control/#
It uses WM_NCCALCSIZE to restrict the text control.

GDI in C not drawing successive objects

Attempting to create a basic drawing program using C and GDI in the Windows API. The idea is that the user clicks and drags to create a rectangle or any other shape that is selected. The size is specified by where the user clicks down and releases (just like any drawing program). I'm having an issue where the first shape that the user draws will be painted to the screen, however anything successive is not. I initially was not drawing the shapes in WM_PAINT, but I read on another thread that I need to do that, so I created a struct to store information about objects that have been painted and those are drawn each time the WM_PAINT message is received.
Here's my code for WM_PAINT
case WM_PAINT:
{
for (int i = 0; i < drawingcount; i++)
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
HPEN hMyPen = CreatePen(mydrawings[i].style, mydrawings[i].thick, RGB(0,255,0));
HPEN hOldPen = SelectObject(hdc, hMyPen);
if (mydrawings[i].shape == RECTANGLE)
{
Rectangle(hdc, mydrawings[i].start_x, mydrawings[i].start_y, mydrawings[i].end_x, mydrawings[i].end_y);
}
else if (mydrawings[i].shape == ELLIPSE)
{
Ellipse(hdc, mydrawings[i].start_x, mydrawings[i].start_y, mydrawings[i].end_x, mydrawings[i].end_y);
}
else if (mydrawings[i].shape == LINE)
{
MoveToEx(hdc, mydrawings[i].start_x, mydrawings[i].start_y, 0);
LineTo(hdc, mydrawings[i].end_x, mydrawings[i].end_y);
}
SelectObject(hdc, hOldPen);
DeleteObject(hMyPen);
//DeleteObject(hOldPen);
EndPaint(hwnd, &ps);
}
}
break;
And here for WM_LBUTTONUP (once user finishes drawing their shape)
case WM_LBUTTONUP:
{
yendclick = GET_Y_LPARAM(lParam);
xendclick = GET_X_LPARAM(lParam);
mydrawings[drawingcount].shape = selected_shape;
mydrawings[drawingcount].start_x = xclick;
mydrawings[drawingcount].start_y = yclick;
mydrawings[drawingcount].end_x = xendclick;
mydrawings[drawingcount].end_y = yendclick;
mydrawings[drawingcount].thick = thickness;
mydrawings[drawingcount].style = style;
drawingcount++;
SendMessage(hwnd, WM_PAINT, wParam, lParam);
}
Struct and enum declarations:
typedef enum myshape
{
RECTANGLE,
ELLIPSE,
LINE,
MAX_SHAPE
} shape;
typedef struct drawing
{
int start_x;
int start_y;
int end_x;
int end_y;
int thick;
int style;
shape shape;
} drawings;
Would very much appreciate any guidance with this!
Don't use PostMessage WM_PAINT, use InvalidateRect and perhaps UpdateWindow instead. See also here: why not to send WM_PAINT manually

C++ - Change vertical pitch of your mouse

The Idea
I was wondering if it's possible to change the pitch of your mouse over the entire screen. To give an example: If you draw a perfect circle with your physical mouse on your table, your screen would draw an oval (with: width > height).
This could be useful if you e.g. used to have a customizable mouse that supported individual m_pitch settings but recently broke down and you can't afford a new one. You could use this program to virtualize those individual settings.
So I went to work and concocted this small program:
#include <windows.h>
#include <iostream>
#include <math.h>
using namespace std;
HHOOK hMouseHook;
bool prev_initialized = false;
bool real_input = true;
MOUSEHOOKSTRUCT prevMouseStruct;
double ratio = 0.5; //cursor should pitch 0.5x as fast as it normally would
double rest = 0;
LRESULT CALLBACK mouseProc (int nCode, WPARAM wParam, LPARAM lParam)
{
MOUSEHOOKSTRUCT * pMouseStruct = (MOUSEHOOKSTRUCT *)lParam;
if (pMouseStruct != NULL){
if(wParam == WM_MOUSEMOVE)
{
printf("Mouse position X = %d Mouse Position Y = %d\n", pMouseStruct->pt.x,pMouseStruct->pt.y);
if(prev_initialized && real_input){
int y_diff = prevMouseStruct.pt.y - pMouseStruct->pt.y;
if(y_diff != 0){
double ratiod_diff = ((double)y_diff) * ratio;
int rounded_diff = (int)round(ratiod_diff);
int newY = prevMouseStruct.pt.y - rounded_diff;
rest += ratiod_diff - rounded_diff;
if(rest > 1){
--rest;
++newY;
}else if(rest < -1){
++rest;
--newY;
}
real_input = false;
pMouseStruct->pt.y = newY;
SetCursorPos(pMouseStruct->pt.x, pMouseStruct->pt.y);
printf("New- Mouse position X = %d Mouse Position Y = %d\n", pMouseStruct->pt.x,newY);
}
}else if(!real_input){
real_input = true;
} else{
prevMouseStruct = *pMouseStruct;
prev_initialized = true;
}
}
}
return CallNextHookEx(hMouseHook, nCode, wParam, lParam);
}
int main()
{
HINSTANCE hInstance = GetModuleHandle(NULL);
hMouseHook = SetWindowsHookEx(WH_MOUSE_LL, mouseProc, hInstance, NULL);
MSG message;
while (GetMessage(&message,NULL,0,0)) {
TranslateMessage( &message );
DispatchMessage( &message );
}
UnhookWindowsHookEx(hMouseHook);
return 0;
}
How?
This program registers all mousemovement-events on the screen and remembers 2 coordinates:
The previous mouse location; e.g.: POINT(100, 100)
The current mouse location; e.g.: POINT(120,150) -> the mouse moved 20px to the right and 50px down
Then, I calculate where I want the cursor to be with the ratio (and some other fancy precision stuff). E.g.: the cursor moves 50px down and the ratio is 0.5 -> the mouse only goes 25px down.
Lastly, I call SetMousePos() with the new y-value to move the cursor to my desired location. (Note: I also try to make sure that this function does not call mouseProc() again by using the boolean real_input as a flag).
The problem
I am running into the following problem: the cursor is not staying at its new y-position. After calling the setMousePos()-function, the mouse shifts to its new position for a split second and then instantly reverts back to its former position. This leaves a makeshift 'afterimage' of the mouse. In this GIF, I move the cursor from the top to the bottom. You can see that it leaves it's after-image that grows larger in distance when you move further away from your starting-position (the starting-position is the position of your mouse when the console opens).
Any feedback would be MUCH appreciated!