Author | Message | Time |
---|---|---|
Dyndrilliac | Recently I have been trying to print the mouse cursor's coordinates just below and to the right of the cursor and have it update in real time, regardless of what windows have focus. I am using GDI to draw the text on screen, and a Mouse Hook to get the coordinates. This code seems to work, save for one minor glitch:[code]#define VC_EXTRALEAN #include <windows.h> #include <stdio.h> void MyInit(); void MyCleanUp(); void DrawCoords(const long X, const long Y); static char Buffer[256]; static HDC MyHDC; void MyInit() { MyHDC = GetDC(NULL); } void MyCleanUp() { ReleaseDC(NULL, MyHDC); } void DrawCoords(const long X, const long Y) { ZeroMemory(Buffer,sizeof(Buffer)); SetBkColor(MyHDC,RGB(0,0,0)); SetTextColor(MyHDC,RGB(255,0,0)); sprintf_s<256>(Buffer,"[X: %i, Y: %i]",X,Y); TextOutA(MyHDC,(X+10),(Y-10),Buffer,strlen(Buffer)); }[/code]The glitch is that the old text strings aren't being removed automatically, and as you move the cursor eventually the screen gets covered in output. I have tried getting the device context just before drawing and releasing it right after, but it didn't work. Here is how/where I am calling the Drawing fxn:[code]LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam) { MOUSEHOOKSTRUCT MyMHS = *(MOUSEHOOKSTRUCT*)lParam; DrawCoords(MyMHS.pt.x,MyMHS.pt.y); return (CallNextHookEx(hMseHook,nCode,wParam,lParam)); }[/code]I need a way to clear away old ouput prior to drawing new ouput. Any suggestions? | September 29, 2008, 9:16 AM |
Ringo | I'm pretty sure you need to use the RedrawWindow() api. Add the static RECT structure, and try the following: [code] static RECT rt; void DrawCoords(const long X, const long Y) { ZeroMemory(Buffer,sizeof(Buffer)); SetBkColor(MyHDC,RGB(0,0,0)); SetTextColor(MyHDC,RGB(255,0,0)); sprintf_s<256>(Buffer,"[X: %i, Y: %i]",X,Y); RedrawWindow(0,rt,0,(int)0x81); sleep(0); rt.left=X+10; rt.top=Y-10; rt.right=rt.left+50; rt.bottom=rt.top+20; TextOutA(MyHDC,rt.left,rt.top,Buffer,strlen(Buffer)); }[/code] im not sure vb6's "doevents" in c++, so I just put a sleep(0) there. I would think it's a good idea to pause a tiny bit, to allow the screen to update, before drawing text -- otherwise RedrawWindow() might draw over you're newly drawn text. hope this helps | September 29, 2008, 12:51 PM |
Yegg | AFAIK, sleep(0) won't do anything. There is no need for a DoEvents equivalent. | September 29, 2008, 5:11 PM |
BreW | In my experience, RedrawWindow() won't redraw overdrawn regions of the screen unless you specify RDW_INVALIDATE, which would set the rect of the window as invalidated. For your situation I would instead recommend using InvalidateRect() which has the same effect, but only for the specified rect. @Yegg: Specifying 0 milliseconds in a call to Sleep() would just force the scheduler to move onto the next thread, equivalent in function to SwitchToThread(). Go figure.. EDIT* I just looked in my WinUser.h, and it seems that Ringo is indeed calling RedrawWindow with flags of RDW_INVALIDATE | RDW_ALLCHILDREN. [code] ... /* * RedrawWindow() flags */ #define RDW_INVALIDATE 0x0001 #define RDW_INTERNALPAINT 0x0002 #define RDW_ERASE 0x0004 #define RDW_VALIDATE 0x0008 #define RDW_NOINTERNALPAINT 0x0010 #define RDW_NOERASE 0x0020 #define RDW_NOCHILDREN 0x0040 #define RDW_ALLCHILDREN 0x0080 ... [/code] | September 29, 2008, 7:11 PM |
Dyndrilliac | Ok this code works absolutely perfectly, except there is some god awful flickering going on.[code]void DrawCoords(const long X, const long Y) { ZeroMemory(Buffer,sizeof(Buffer)); HDC MyHDC = GetDC(NULL); RECT MyRect; MyRect.top = Y-5; MyRect.left = X+5; MyRect.bottom = Y-40; MyRect.right = X+40; InvalidateRect(NULL, &MyRect,false); SetBkColor(MyHDC,RGB(0,0,0)); SetTextColor(MyHDC,RGB(255,0,0)); sprintf_s<256>(Buffer,"{X: %i,Y: %i}",X,Y); TextOutA(MyHDC,(X+10),(Y-10),Buffer,strlen(Buffer)); ReleaseDC(NULL, MyHDC); } LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam) { if (nCode == HC_ACTION) { MOUSEHOOKSTRUCT MyMHS = *(MOUSEHOOKSTRUCT*)lParam; DrawCoords(MyMHS.pt.x,MyMHS.pt.y); } return (CallNextHookEx(hMseHook,nCode,wParam,lParam)); }[/code]Keep in mind im using global mouse hook. Is there any way to get the window thread id of the parent hwnd for the process with only the process handle or process id? | September 30, 2008, 3:48 AM |
Ringo | [quote author=brew link=topic=17677.msg179990#msg179990 date=1222715462] For your situation I would instead recommend using InvalidateRect() which has the same effect, but only for the specified rect. [/quote] RedrawWindow() can also redraw a given rect, if given one -- leaving the handle to the window as null, will redraw the screen by defalt. If you don't supply a rect, or a handle to the area of the screen/window you want redrawn, then it will redraw the whole screen/window. [quote author=Dyndrilliac link=topic=17677.msg179995#msg179995 date=1222746522] Ok this code works absolutely perfectly, except there is some god awful flickering going on.[/quote] Try useing sleep(0) right after you redraw the screen -- that should stop it. When I tested it with VB6, RedrawWindow worked fine for me, but if I didn't make a call to doevents() it would flicker/redraw over the text. Try sleep(0). You could also draw the cords on a loop useing the GetCursorPos() api, which is what I did when I tested this. Just be sure to compare the result of GetCursorPos() with the cords of the last redraw -- if they are not the same, then draw, other wise don't. Somthing like: GetCursorPos(pos) If(lpos.x==pos.x && lpos.y==pos.y) return; lpos=pos setbackcolor settextcolor redrawwindow sleep(0) textoutA | October 1, 2008, 4:45 AM |
Win32 | [quote] im not sure vb6's "doevents" in c++, so I just put a sleep(0) there. [/quote] LOL. Doesn't get any more clueless than that. | October 24, 2008, 12:01 AM |
Ringo | [quote author=Win32 link=topic=17677.msg180146#msg180146 date=1224806488] LOL. Doesn't get any more clueless than that. [/quote] Doesn't get any less constructive than that. I hope you're aware, the vb6 rtcDoEvents function is not like that of the C++ equivalent DoEvents. The one in the vb6 runtime dll make's a call to sleep, where as C++ does not. Since the idea is, to allow the system to redraw an area of the screen before you draw over it, rather than having it redraw the screen after you have drawn the text, sleep(0) seemed like a reassionable option. Go check MSDN: [quote="DoEvents@msdn"] Unlike Visual Basic 6.0, the DoEvents method does not call the Sleep method. [/quote] [quote="Sleep@msdn"] Specify zero (0) to indicate that this thread should be suspended to allow other waiting threads to execute. [/quote] | October 24, 2008, 3:46 AM |
BreW | [quote author=Win32 link=topic=17677.msg180146#msg180146 date=1224806488] [quote] im not sure vb6's "doevents" in c++, so I just put a sleep(0) there. [/quote] LOL. Doesn't get any more clueless than that. [/quote] ... rtcDoEvents: [tt] .text:73447EDF push esi .text:73447EE0 push edi .text:73447EE1 call _HostDoEvents@0 ; HostDoEvents() .text:73447EE6 mov esi, eax .text:73447EE8 [size=4][color=red]xor edi, edi[/color][/size] .text:73447EEA .text:73447EEA loc_73447EEA: ; CODE XREF: rtcDoEvents()+1B038 .text:73447EEA cmp esi, 0FFFFFFFFh .text:73447EED jz loc_73462F1C .text:73447EF3 cmp dword_73531340, edi .text:73447EF9 jnz loc_73462F10 .text:73447EFF .text:73447EFF loc_73447EFF: ; CODE XREF: rtcDoEvents()+1B043 .text:73447EFF mov eax, hMem .text:73447F04 cmp eax, edi .text:73447F06 jnz loc_73462F2D .text:73447F0C .text:73447F0C loc_73447F0C: ; CODE XREF: rtcDoEvents()+1B049 .text:73447F0C ; rtcDoEvents()+1B073 .text:73447F0C [size=4][color=red]push edi ; dwMilliseconds[/color][/size] .text:73447F0D [size=4][color=red]call ds:__imp__Sleep@4 ; Sleep(x)[/color][/size] .text:73447F13 mov ax, si .text:73447F16 pop edi .text:73447F17 pop esi .text:73447F18 retn [/tt] | October 24, 2008, 7:21 PM |