The MASM Forum

General => The Workshop => Topic started by: NoCforMe on March 01, 2014, 02:35:15 PM

Title: How to receive mouse messages for the entire screen?
Post by: NoCforMe on March 01, 2014, 02:35:15 PM
Well, I'm back. (Apparently I stayed away long enough for my account to be canceled.)

My question this time is this: how can I tap into mouse messages for the entire Windows screen?

What I'm thinking of are programs that can use the mouse outside of their own windows/client areas. One example that I use is my paint program, Paint Shop Pro, which has a screen-capture function that allows me to marquee-select any area of any window on the desktop. Dunno how they do this, but it works.

I thought of trying to subclass the desktop window:

; Subclass the desktop:
CALL GetDesktopWindow
MOV DesktopHandle, EAX
INVOKE SetWindowLong, DesktopHandle, GWL_WNDPROC, ADDR DesktopProc
MOV DesktopProcPtr, EAX


but then I read more about SetWindowLong(): if you want to change the address of the window procedure for a window, "You cannot change this attribute if the window does not belong to the same process as the calling thread." D'oh!

So how could I do this? What I'm trying to do is pretty simple: I'd just like to be able to maquee-select an area of the screen, then display the dimensions in pixels of this area. Seems like that should be pretty simple, no?

Edit: By "marquee select" what I mean is to click anywhere on the screen and drag an outline, then measure the rectangle, possibly while being dragged, or after the mouse button is let go.

Thanks in advance for any help!

(Oh, and I did try traditional mouse capture (via SetCapture() ); couldn't get that to work either.)
Title: Re: How to receive mouse messages for the entire screen?
Post by: dedndave on March 01, 2014, 02:58:39 PM
i don't think they let you subclass the desktop window
but, you might be able capture the mouse (problem - if the OS or some other program captures, you lose capture)
maybe a hook on the mouse ?
the WindowFromPoint function might also be useful
Title: Re: How to receive mouse messages for the entire screen?
Post by: NoCforMe on March 01, 2014, 03:05:32 PM
Quote from: dedndave on March 01, 2014, 02:58:39 PM
the WindowFromPoint function might also be useful

Hmm; not sure how knowing which window the mouse is over could be useful. All I know is that PSP lets you click and drag an outline anywhere on the screen (as well as capture what's inside the rectangle).
Title: Re: How to receive mouse messages for the entire screen?
Post by: MichaelW on March 01, 2014, 07:23:42 PM
One method is to capture the mouse.

;==============================================================================
; Build as a console app.
;==============================================================================
include \masm32\include\masm32rt.inc
;==============================================================================
    .data
    .code
;==============================================================================
DlgProc proc hwndDlg:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
    SWITCH uMsg
        CASE WM_INITDIALOG
        CASE WM_LBUTTONDOWN
            invoke SetCapture, hwndDlg
        CASE WM_LBUTTONUP
            invoke ReleaseCapture
        CASE WM_MOUSEMOVE
            loc 0,0
            ;----------------------------------------------------------
            ; The 16-bit cursor coordinates returned in lParam must be
            ; sign-extended to 32 bits because client coordinates to
            ; the left of and/or above the client area are negative.
            ;----------------------------------------------------------
            mov eax, lParam
            mov edx, eax
            movsx eax, ax
            shr edx, 16
            movsx edx, dx
            printf("%d     %d     ",eax,edx)
        CASE WM_COMMAND
            SWITCH wParam
                CASE IDCANCEL
                    invoke EndDialog, hwndDlg, NULL
            ENDSW
        CASE WM_CLOSE
            invoke EndDialog, hwndDlg, NULL
    ENDSW
    return 0
DlgProc endp
;==============================================================================
start:
;==============================================================================
    Dialog "Test", \
           "MS Sans Serif",10, \
           WS_OVERLAPPED or WS_SYSMENU or DS_CENTER, \
           0,0,0,80,60,1024
    CallModalDialog NULL,0,DlgProc,NULL
    exit
;==============================================================================
end start


I have used this technique to capture a window to a bitmap file, but I have never tried dragging a selection rectangle, or anything similar.


Title: Re: How to receive mouse messages for the entire screen?
Post by: hutch-- on March 01, 2014, 07:46:56 PM
Have a look at a tool in the "tools" directory of MASM32 called "Getcolor". It shows how to use GetCapture".
Title: Re: How to receive mouse messages for the entire screen?
Post by: NoCforMe on March 02, 2014, 03:10:57 AM
I don't seem to have that program in my tools folder. I got MASM32 more than a year ago; has it been added since then?. Any chance you could post a zip of it here? (Don't want to reload the package just yet.)

MichaelW, I don't see how that could work for me. Wouldn't the mouse click (resulting in WM_LBUTTONDOWN being received) have to be in one of MY windows? Otherwise, I won't get this message and won't be able to capture the mouse. Or am I missing something there? Remember, I want to be able to click anywhere on the screen, not necessarily in any of my program's areas.
Title: Re: How to receive mouse messages for the entire screen?
Post by: dedndave on March 02, 2014, 03:56:01 AM
when a window has mouse capture, all mouse messages (movement, clicks) are sent to the window that has capture

the only trick to mouse capture is understanding the relationship with WM_CAPTURECHANGED
i have played with it quite a bit (movable marker lines, sizable windows, etc)
rather than executing "release" code, directly....
you just call ReleaseCapture
then put the "release" code in the WM_CAPTURECHANGED handler
that way, if the system releases capture (for whatever reason) - or another window grabs capture, your release code is executed

i mentioned WindowFromPoint because of the following scenerio....
let's say you have capture - all the mouse messages come to your window
in some cases, you may want to pass those messages to the window that would have received them if you didn't have capture
so, you could get WindowFromPoint, then SendMessage to "forward" messages

i really think that a mouse hook is more in order for this, though - you'll have to experiment

http://msdn.microsoft.com/en-us/library/windows/desktop/ms632589%28v=vs.85%29.aspx (http://msdn.microsoft.com/en-us/library/windows/desktop/ms632589%28v=vs.85%29.aspx)

the problem is - the Desktop uses the drag-selection outline to select a group of icons
that's very different from selecting a graphic region
it might require some sort of Shell Extension Handler

http://msdn.microsoft.com/en-us/library/windows/desktop/cc144067%28v=vs.85%29.aspx (http://msdn.microsoft.com/en-us/library/windows/desktop/cc144067%28v=vs.85%29.aspx)

hopefully, that gives you some ideas   :biggrin:

Title: Re: How to receive mouse messages for the entire screen?
Post by: dedndave on March 02, 2014, 04:04:32 AM
if you find that mouse capture is workable....

here is a simple example that demonstrates the use of WM_CAPTURECHANGED
it uses mouse capture to create movable dividers
Title: Re: How to receive mouse messages for the entire screen?
Post by: qWord on March 02, 2014, 11:57:52 AM
Quote from: NoCforMe on March 01, 2014, 02:35:15 PMEdit: By "marquee select" what I mean is to click anywhere on the screen and drag an outline, then measure the rectangle, possibly while being dragged, or after the mouse button is let go.
A simple solution would be to create a snapshot of the current desktop, which is present in a popup window that covers the desktop. The actual selection/measurement is then done by the popup window.
If the content of the Desktop does change while "measurement", layered windows may be a solution (e.g. a semi-transparent overlay).
Title: Re: How to receive mouse messages for the entire screen?
Post by: farrier on March 02, 2014, 12:23:31 PM
For mouse capture info, I got a lot of mileage from Iczelion's tutorial 24.  It had everything and more than what I needed.

hth,

farrier
Title: Re: How to receive mouse messages for the entire screen?
Post by: jj2007 on March 02, 2014, 01:03:17 PM
Quote from: qWord on March 02, 2014, 11:57:52 AMA simple solution would be to create a snapshot of the current desktop, which is present in a popup window that covers the desktop. The actual selection/measurement is then done by the popup window.

Similar: A transparent window that draws rectangles using GetWindowDC. I attach a draft version in plain Masm32 - no time to finish it, but you'll get the idea.
Title: Re: How to receive mouse messages for the entire screen?
Post by: TouEnMasm on March 02, 2014, 06:20:21 PM

The API TrackMouseEvent can be of good use.
Title: Re: How to receive mouse messages for the entire screen?
Post by: qWord on March 03, 2014, 05:43:33 AM
In the attachment an example using layered windows. The trick is to create an semi-transparent overlay whereas the alpha value is nonzero - due this all mouse messages are send to the overlay window.

include \masm32\include\masm32rt.inc
.686
.mmx
.xmm

IDBTN_SELECT        EQU 100
IDCTL_SELECTION     EQU 101
COLOR_KEY           EQU 0ff00ffh
CONST_ALPHA         EQU 40          ; for 32bpp: 1+, 16bpp: 5+
COLOR_OVERLAY       EQU 0333333h
DELTA_WAIT          EQU 100
FRAME_WIDTH         EQU 3
FRAME_COLOR         EQU 0ffh
WM_NEW_SELECTION    EQU WM_USER+100

WndProc proto hWnd:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM
OverlayProc proto hWnd:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM
FrameProc proto hWnd:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM

.const
    szMainClass     db "Win32Class",0
    szOverlayClass  db "OverlayClass32",0
    szFrameClass    db "FrameClass32",0
.data?
    g_hInstance     HINSTANCE ?

    ;/* gloabl variables for simplification :-D */
    g_hMainWnd      HWND ?
    g_hOverlayWnd   HWND ?
    g_hStaticImg    HWND ?
    g_hStaticTxt    HWND ?
    g_hWndFrame     HWND ?
    g_rcFrame       RECT <>

.code
main proc
LOCAL wcex:WNDCLASSEX
LOCAL msg:MSG

    mov g_hInstance,rv(GetModuleHandle,0)
    mov wcex.hInstance,eax
    mov wcex.cbSize,SIZEOF WNDCLASSEX
    mov wcex.style, CS_HREDRAW or CS_VREDRAW
    mov wcex.lpfnWndProc, OFFSET WndProc
    mov wcex.cbClsExtra,NULL
    mov wcex.cbWndExtra,0
    mov wcex.hbrBackground,rv(GetStockObject,WHITE_BRUSH)
    mov wcex.lpszMenuName,NULL
    mov wcex.lpszClassName,OFFSET szMainClass
    mov wcex.hIcon,rv(LoadIcon,NULL,IDI_APPLICATION)
    mov wcex.hIconSm,eax
    mov wcex.hCursor,rv(LoadCursor,NULL,IDC_ARROW)
    invoke RegisterClassEx, ADDR wcex
    mov wcex.lpfnWndProc, OFFSET OverlayProc
    mov wcex.hbrBackground,0
    mov wcex.lpszClassName,OFFSET szOverlayClass
    invoke RegisterClassEx, ADDR wcex
    mov wcex.lpfnWndProc, OFFSET FrameProc
    mov wcex.lpszClassName,OFFSET szFrameClass
    invoke RegisterClassEx, ADDR wcex
    fn CreateWindowEx,0,OFFSET szMainClass,"select region",WS_VISIBLE or WS_SYSMENU or WS_SIZEBOX or WS_MINIMIZEBOX or WS_MAXIMIZEBOX or WS_CLIPCHILDREN,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,0,0,g_hInstance,0

    .while 1
        invoke GetMessage,ADDR msg,NULL,0,0
        .break .if !eax || eax == -1
        invoke TranslateMessage, ADDR msg
        invoke DispatchMessage, ADDR msg
    .endw

    invoke ExitProcess,msg.wParam

main endp

;/* make sure that left <= right and top <= bottom */
checkRect proc pRect: ptr RECT

    mov eax,pRect
    mov ecx,[eax].RECT.left
    mov edx,[eax].RECT.right
    .if ecx > edx
        mov [eax].RECT.left,edx
        mov [eax].RECT.right,ecx
    .endif
    mov ecx,[eax].RECT.top
    mov edx,[eax].RECT.bottom
    .if ecx > edx
        mov [eax].RECT.top,edx
        mov [eax].RECT.bottom,ecx
    .endif
    ret

checkRect endp

;/* main window */
WndProc proc uses ebx esi edi hWnd:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM
LOCAL sz[128]:CHAR

    .if uMsg == WM_CLOSE
        invoke DestroyWindow,hWnd
    .elseif uMsg == WM_DESTROY
        .if rv(SendMessage,g_hStaticImg,STM_GETIMAGE,IMAGE_BITMAP,0)
            fn DeleteObject,eax
        .endif
        fn PostQuitMessage,NULL
    .elseif uMsg == WM_CREATE
    mrm g_hMainWnd,hWnd
        fn CreateWindowEx,0,"button","Select",WS_VISIBLE or WS_CHILD,0,0,100,30,hWnd,IDBTN_SELECT,g_hInstance,0
        fnx g_hStaticImg = CreateWindowEx,0,"static",0,WS_CHILD or WS_VISIBLE or SS_BITMAP or WS_BORDER,5,35,100,100,hWnd,0,g_hInstance,0
        fnx g_hStaticTxt = CreateWindowEx,0,"static",0,WS_CHILD or WS_VISIBLE,103,0,200,30,hWnd,0,g_hInstance,0
        fn SendMessage,g_hStaticImg,STM_SETIMAGE,IMAGE_BITMAP,rv(CreateCompatibleBitmap,rv(GetDC,0),10,10)
    .elseif uMsg == WM_COMMAND && wParam == BN_CLICKED SHL 16 OR IDBTN_SELECT
        .if !g_hOverlayWnd
            fnx esi = GetSystemMetrics,SM_CXSCREEN
            fnx edi = GetSystemMetrics,SM_CYSCREEN

            ;/* hide this window and create screen-overlay */
            invoke ShowWindow,hWnd,SW_MINIMIZE
            fnx g_hOverlayWnd = CreateWindowEx,WS_EX_LAYERED OR WS_EX_TOPMOST,OFFSET szOverlayClass,0,WS_VISIBLE OR WS_POPUP,0,0,esi,edi,0,0,g_hInstance,0
        .endif
    .elseif uMsg == WM_NEW_SELECTION
        mov g_hOverlayWnd,0
        mov eax,wParam
        .if eax
            ;/* process new selection */
            mov ecx,[eax].RECT.right
            mov edx,[eax].RECT.bottom
            sub ecx,[eax].RECT.left
            sub edx,[eax].RECT.top
            fn wsprintf,&sz,"x: %i, y: %i, w: %i, h: %i",[eax].RECT.left,[eax].RECT.top,ecx,edx
            fn SendMessage,g_hStaticTxt,WM_SETTEXT,0,&sz

            push rv(SendMessage,g_hStaticImg,STM_GETIMAGE,IMAGE_BITMAP,0)
            fn SendMessage,g_hStaticImg,STM_SETIMAGE,IMAGE_BITMAP,lParam
            pop eax
            .if eax
                invoke DeleteObject,eax
            .endif
        .endif
    .else
        invoke DefWindowProc,hWnd,uMsg,wParam,lParam
        ret
    .endif

    xor eax,eax
    ret
WndProc endp

;/**
; * This window is transparent and occupies the whole screen.
; * Actual the window is draw with an low alpha value to make sure that
; * mouse messages are received.
; * When dragging starts, a layered window (hit-transparent) is created that
; * shows the selection-frame.
; */
OverlayProc proc uses ebx esi edi hWnd:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM
LOCAL ps:PAINTSTRUCT
LOCAL hBr:HBRUSH
LOCAL rect:RECT,w:SDWORD,h:SDWORD

    .if uMsg == WM_CLOSE || (uMsg == WM_KEYDOWN && wParam == VK_ESCAPE)
        fn ShowWindow,g_hMainWnd,SW_RESTORE
        fn SendMessage,g_hMainWnd,WM_NEW_SELECTION,0,0
        fn DestroyWindow,hWnd
    .elseif uMsg == WM_DESTROY
    .elseif uMsg == WM_CREATE
        ;/**
        ; *  Draw window with alpha value > 0 thus
        ; *  mouse messages are send to this window.
        ; */
        invoke SetLayeredWindowAttributes,hWnd,0,CONST_ALPHA,LWA_ALPHA
        invoke SetForegroundWindow,hWnd
        mov g_hWndFrame,0
    .elseif uMsg == WM_LBUTTONDOWN
        .if !g_hWndFrame
            ;/* show frame */
            fnx esi = GetSystemMetrics,SM_CXSCREEN
            fnx edi = GetSystemMetrics,SM_CYSCREEN
            fnx g_hWndFrame = CreateWindowEx,WS_EX_LAYERED or WS_EX_TRANSPARENT or WS_EX_TOPMOST,OFFSET szFrameClass,0,WS_VISIBLE OR WS_POPUP,0,0,1,1,hWnd,0,g_hInstance,0
            fn GetCursorPos,&g_rcFrame
        .endif
    .elseif uMsg == WM_LBUTTONUP
        .if g_hWndFrame
            mov g_hWndFrame,0

            ;/* destroy this window (and g_hWndFrame) */
            invoke DestroyWindow,hWnd
            invoke Sleep,DELTA_WAIT

            ;/* get image from region */
            fn RtlMoveMemory,&rect,&g_rcFrame,RECT
            fn checkRect,&rect
            mov ecx,rect.right
            mov edx,rect.bottom
            sub ecx,rect.left
            sub edx,rect.top
            mov w,ecx
            mov h,edx
            fnx esi = GetDC,0
            fnx ebx = CreateCompatibleDC,esi
            fnx edi = SelectObject,ebx,rv(CreateCompatibleBitmap,esi,w,h)
            invoke BitBlt,ebx,0,0,w,h,esi,rect.left,rect.top,SRCCOPY
            fnx edi = SelectObject,ebx,edi
            fn DeleteDC,ebx

            ;/* send result */
            fn SendMessage,g_hMainWnd,WM_NEW_SELECTION,&rect,edi

            ;/* show main-window */
            invoke ShowWindow,g_hMainWnd,SW_RESTORE
        .endif
    .elseif uMsg == WM_MOUSEMOVE
        .if g_hWndFrame
            ;/* update window position (frame) */
            fn GetCursorPos,&g_rcFrame.right
            fn RtlMoveMemory,&rect,&g_rcFrame,RECT
            fn checkRect,&rect
            mov ecx,rect.right
            mov edx,rect.bottom
            sub ecx,rect.left
            sub edx,rect.top
            invoke SetWindowPos,g_hWndFrame,0,rect.left,rect.top,ecx,edx,SWP_NOZORDER
        .endif
    .elseif uMsg == WM_PAINT
        invoke BeginPaint,hWnd,ADDR ps
        mov ecx,ps.rcPaint.right
        mov edx,ps.rcPaint.bottom
        sub ecx,ps.rcPaint.left
        sub edx,ps.rcPaint.top
        mov rect.right,ecx
        mov rect.bottom,edx

        fnx ebx = CreateCompatibleDC,ps.hdc
        fnx edi = SelectObject,ebx,rv(CreateCompatibleBitmap,ps.hdc,rect.right,rect.bottom)

        fnx hBr = SelectObject,ebx,rv(CreateSolidBrush,COLOR_OVERLAY)
        invoke BitBlt,ebx,0,0,rect.right,rect.bottom,ebx,0,0,PATCOPY
        fn DeleteObject,rv(SelectObject,ebx,hBr)
       
        fn BitBlt,ps.hdc,ps.rcPaint.left,ps.rcPaint.top,rect.right,rect.bottom,ebx,0,0,SRCCOPY
        fn DeleteObject,rv(SelectObject,ebx,edi)
        fn DeleteDC,ebx

        invoke EndPaint,hWnd,ADDR ps
    .else
        invoke DefWindowProc,hWnd,uMsg,wParam,lParam
        ret
    .endif

    xor eax,eax
    ret

OverlayProc endp

;/* This window is hit-transparent and shows the selection-frame */
FrameProc proc uses ebx esi edi hWnd:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM
LOCAL ps:PAINTSTRUCT
LOCAL hBr:HBRUSH,hPen:HPEN
LOCAL rect:RECT

    .if uMsg == WM_DESTROY
    .elseif uMsg == WM_CREATE
        invoke SetLayeredWindowAttributes,hWnd,COLOR_KEY,128,LWA_COLORKEY OR LWA_ALPHA
    .elseif uMsg == WM_PAINT
        fn GetClientRect,hWnd,&rect
        invoke BeginPaint,hWnd,ADDR ps
        fnx ebx = CreateCompatibleDC,ps.hdc
        fnx edi = SelectObject,ebx,rv(CreateCompatibleBitmap,ps.hdc,rect.right,rect.bottom)

        fnx hBr = SelectObject,ebx,rv(CreateSolidBrush,COLOR_KEY)
        invoke BitBlt,ebx,0,0,rect.right,rect.bottom,ebx,0,0,PATCOPY
        fnx hPen = SelectObject,ebx,rv(CreatePen,PS_SOLID,FRAME_WIDTH,FRAME_COLOR)

        invoke Rectangle,ebx,rect.left,rect.top,rect.right,rect.bottom
        fn DeleteObject,rv(SelectObject,ebx,hPen)
        fn DeleteObject,rv(SelectObject,ebx,hBr)

        fn BitBlt,ps.hdc,0,0,rect.right,rect.bottom,ebx,0,0,SRCCOPY
        fn DeleteObject,rv(SelectObject,ebx,edi)
        fn DeleteDC,ebx

        invoke EndPaint,hWnd,ADDR ps
    .else
        invoke DefWindowProc,hWnd,uMsg,wParam,lParam
        ret
    .endif
    xor eax,eax
    ret
FrameProc endp
end main


Quote from: jj2007 on March 02, 2014, 01:03:17 PMSimilar: A transparent window that draws rectangles using GetWindowDC.
you might describe that more detailed.
Title: Re: How to receive mouse messages for the entire screen?
Post by: jj2007 on March 03, 2014, 07:00:06 PM
Quote from: qWord on March 03, 2014, 05:43:33 AM
Quote from: jj2007 on March 02, 2014, 01:03:17 PMSimilar: A transparent window that draws rectangles using GetWindowDC.
you might describe that more detailed.

Basically, you paint rectangles on a window that doesn't paint its background.

Simple example attached, in plain Masm32 (exe, asm and asc for the proud RichMasm user ;)). Actually, I needed this app for something completely unrelated to this thread, so thanks to the OP for pushing me a little bit :t

EDIT: Version 2 leaves W=nnn, H=nnn on top right corner of each rectangle.
Title: Re: How to receive mouse messages for the entire screen?
Post by: qWord on March 04, 2014, 12:33:16 AM
Quote from: jj2007 on March 03, 2014, 07:00:06 PMBasically, you paint rectangles on a window that doesn't paint its background.
That method does no longer work due to the desktop window manager (vista+), which compose the final image from buffers - the applications no longer draw directly to the screen DC.
Title: Re: How to receive mouse messages for the entire screen?
Post by: jj2007 on March 04, 2014, 04:04:08 AM
Quote from: qWord on March 04, 2014, 12:33:16 AM
Quote from: jj2007 on March 03, 2014, 07:00:06 PMBasically, you paint rectangles on a window that doesn't paint its background.
That method does no longer work due to the desktop window manager (vista+), which compose the final image from buffers - the applications no longer draw directly to the screen DC.

It works perfectly under Win7, provided you are using a "classic" theme. With Aero, you get indeed white rectangles instead of frames.
Title: Re: How to receive mouse messages for the entire screen?
Post by: hool on March 14, 2014, 10:10:34 PM
You need to handle raw input events. RegisterRawInputDevices + GetRawInputData. This is what some games use. Some firewalls might raise alarm regarding this.
Title: Re: How to receive mouse messages for the entire screen?
Post by: Tedd on March 21, 2014, 03:05:39 AM
1. Take a snapshot of the whole screen
2. Capture the mouse pointer
3. Create a popup window (with on-top state) to cover the screen
4. Bitblt the screenshot to your window
5. Change the pointer shape (crosshair?) to give some user feedback, and allow the user to drag an outline, or whatever else
6. Respond to the click and save the image portion to file
7. Destroy your popup window, and free your resources (bitmaps, DCs, etc)
8. Release the mouse pointer

Easy?
Title: Re: How to receive mouse messages for the entire screen?
Post by: NoCforMe on March 25, 2014, 10:04:45 AM
@Tedd: With all due respect, that sounds like a ... klugey solution at best.

In my original post I mentioned how a piece of commercial software I use (Paint Shop Pro) has this functionality built in. Is anyone here familiar with this program? I'm still using their version  7.00, which by now is pretty ancient, but still works fine  for me. I'll bet (though I'd have to try it) that it would still work under Vista, perhaps even Windows 7, including the nifty screen-lasso function.

Also, regarding the solution suggested by Dave (I think) earlier, ugh: hadn't figured on having to write a DLL for my little app. I've never written one and frankly don't really have any desire to do so ...
Title: Re: How to receive mouse messages for the entire screen?
Post by: jj2007 on March 25, 2014, 10:55:35 AM
Quote from: NoCforMe on March 25, 2014, 10:04:45 AM.. (Paint Shop Pro) has this functionality built in. Is anyone here familiar with this program? I'm still using their version  7.00, which by now is pretty ancient, but still works fine  for me. I'll bet (though I'd have to try it) that it would still work under Vista, perhaps even Windows 7, including the nifty screen-lasso function.

Version 4.18 works fine under Windows 7...
Title: Re: How to receive mouse messages for the entire screen?
Post by: Tedd on March 26, 2014, 06:12:04 AM
Quote from: NoCforMe on March 25, 2014, 10:04:45 AM
@Tedd: With all due respect, that sounds like a ... klugey solution at best.

In my original post I mentioned how a piece of commercial software I use (Paint Shop Pro) has this functionality built in. Is anyone here familiar with this program? I'm still using their version  7.00, which by now is pretty ancient, but still works fine  for me. I'll bet (though I'd have to try it) that it would still work under Vista, perhaps even Windows 7, including the nifty screen-lasso function.

Also, regarding the solution suggested by Dave (I think) earlier, ugh: hadn't figured on having to write a DLL for my little app. I've never written one and frankly don't really have any desire to do so ...
Windows doesn't provide a direct way to do this, and you're trying to copy the contents of other windows - any solution is going to be some kind of kludge. This is the cleanest way I could think to do it.

I have just tried with PSP7 and it works almost the same way minus the intermediate popup window - the capture rectangle is drawn directly on to the screen (xor-ed so that xor-ing again will remove it), with the hope that you won't to interact with any other windows during that time (you still can via the keyboard), and the snapshot is actually taken with the next click. This is a fairly hacky-but-it-works-in-most-cases approach.

For an immediate capture (full-screen, window, static area), you can obviously just take the snapshot directly from the screen, but in the case of capturing a user-drawn rectangle I did suggest taking the snapshot first and then using it on a popup window for a few reasons:
- you're going to be drawing some kind of interface on top of everything else, which shouldn't interfere with any other windows' contents (even in the case of xor-ing simple lines, this leaves artefacts if their window contents change during that time);
- it should avoid problems caused by composition rendering on later windows version (untested whether it would be a problem, but it doesn't hurt either);
- it makes sense to capture what was on the screen when the capture was requested, and not some seconds later after a rectangle has been drawn around the..... oops, it's changed and now I missed it.

Any less kludgey magic solutions welcome.
Title: Re: How to receive mouse messages for the entire screen?
Post by: hutch-- on March 26, 2014, 02:42:13 PM
Tedd is right, doing a BitBlt() on the screen (with or without the calling window) then chop out the bit you want that you mark out with the mouse rectangle. From memory you just BitBlt() the rect area that is marked out with the mouse reading the mouse down then up messages.
Title: Re: How to receive mouse messages for the entire screen?
Post by: NoCforMe on April 19, 2014, 07:08:36 AM
Quote from: Tedd on March 26, 2014, 06:12:04 AM
I have just tried with PSP7 and it works almost the same way minus the intermediate popup window - the capture rectangle is drawn directly on to the screen (xor-ed so that xor-ing again will remove it), with the hope that you won't to interact with any other windows during that time (you still can via the keyboard), and the snapshot is actually taken with the next click. This is a fairly hacky-but-it-works-in-most-cases approach.

For an immediate capture (full-screen, window, static area), you can obviously just take the snapshot directly from the screen [...]

Ackshooly, that's exactly what I want. Take a snapshot of the screen as it is at the time of lassoing, then size an area. No concern about subsequent changes to window contents.

Actually, I don't even want the contents of the screen: I only want to be able to draw a lasso and determine the size of the lassoed area.  Like PSP 7 does, I can indicate the size directly on the screen (I think by creating a cursor that's an image of the size string--x X y--so no other interface or popup windows needed). This isn't perfect--with my browser (Opera), it left some garbage on the screen during the capture--but it would work well enough for my purposes.

So can you tell me how to do that? I don't know how to access the screen, nor how to conduct mouse operations outside of my client windows. Oh, and the way PSP works,  when you capture the screen, the PSP client windows completely disappear.

This might in itself be klugey, but it would satisfy the requirements of my little project.